Class文件是啥,有什么用和字节码有什么关系
创始人
2024-06-03 13:19:47
0

本文概述:
在上一个文章我们谈论了关于字节码的信息.
这里我们来看看 Class 文件是什么

Class 文件是什么

还是老样子, 不直接说是啥, 应该先了解为什么需要.

其实你看这个名字就了解到了, 肯定和类有关系. 我们思考一下, 我们学习的时候肯定都有了解过, Java 是跨平台的, 那么如何跨平台呢?

答案就是这个 Class 文件, 名字很明显, 保存的就是一个类的信息.

也就是说, 这个 Class 文件保存了一个类的所有信息, Class 文件是可以开平台的 (注: 拓展思考一下, 你可能了解过 JVM 里面也有 Class 类信息, 事实上,Class 类信息就是根据这个 Class 文件而产生的, 所以说不同平台, 虚拟机不同, 只要虚拟机是按照规范设计的, 就可以加载这个 Class 文件.)

Class 文件里面存储了类的所有信息, 其实到这里, 一定要做的是,Class 文件里面 <都需要存储哪些东西>,如果你知道, 也不要去回忆他存储哪些东西, <最重要的是,一个Class里面有哪些信息>

由问题来思考需要保存哪些信息:

  1. 版本问题: 1.8 和 1.7 的 Class 文件能通用吗?, 肯定不行, 那么就需要保存版本号
  2. 下面分析就简单多了, 我们编写类的时候有啥
    1. 类信息: 类全限定名, 修饰符, 如果实现了父类, 是不是还需要父类的全限定名和修饰符. 或者说实现了接口, 接口的全限定名, 修饰符等
    2. 方法信息: 一个类中有很多方法吧, 方法名, 修饰符, 返回值, 参数.
    3. 属性信息: 比如说基本数据类型, 引用对象等等.

有个很重要的就是: Class 常量池, 这货在类加载器加载了 Class 文件之后就会变成 Class 运行时常量池, 等会会介绍一下.

下面来主要来介绍一下 Class 文件存储属性, 因为

Class 文件如何存储属性

Class 文件中一个结构,Constant Pool, 我们可以叫他 Class 静态常量池

![[Pasted image 20230314134804.png]]

Tag 值是啥啊, 到底是如何存储的, 图片更直观

常量池里面都存储哪些信息呢?

Classfile /E:/VSCODE_FILE/Test/src/main/java/org/example/jvm/ConstantPoolTest.classLast modified 2023-3-14; size 693 bytes                                                MD5 checksum ac8bce83662ec1afa8a0ae98d8ad91c9                                          Compiled from "ConstantPoolTest.java"                                                  
public class org.example.jvm.ConstantPoolTest                                            minor version: 0                                                                       major version: 52                                                                      flags: ACC_PUBLIC, ACC_SUPER                                                           
Constant pool:                // 这里是静态常量池哦!!!                                                           #1 = Methodref          #16.#42        // java/lang/Object."":()V               #2 = Fieldref           #15.#43        // org/example/jvm/ConstantPoolTest.int_num:I  #3 = Fieldref           #15.#44        // org/example/jvm/ConstantPoolTest.char_num:C #4 = Fieldref           #15.#45        // org/example/jvm/ConstantPoolTest.short_num:S#5 = Float              130.0f                                                        #6 = Fieldref           #15.#46        // org/example/jvm/ConstantPoolTest.float_num:F#7 = Double             140.0d#9 = Fieldref           #15.#47        // org/example/jvm/ConstantPoolTest.double_num:D#10 = Fieldref           #15.#48        // org/example/jvm/ConstantPoolTest.byte_num:B#11 = Long               3333l#13 = Fieldref           #15.#49        // org/example/jvm/ConstantPoolTest.long_num:J#14 = Fieldref           #15.#50        // org/example/jvm/ConstantPoolTest.boolean_flag:Z#15 = Class              #51            // org/example/jvm/ConstantPoolTest#16 = Class              #52            // java/lang/Object#17 = Utf8               int_num#18 = Utf8               I#19 = Utf8               char_num#20 = Utf8               C#21 = Utf8               short_num#22 = Utf8               S#23 = Utf8               float_num#24 = Utf8               F#25 = Utf8               double_num#26 = Utf8               D#27 = Utf8               byte_num#28 = Utf8               B#29 = Utf8               long_num#30 = Utf8               J#31 = Utf8               long_delay_num#32 = Utf8               boolean_flag#33 = Utf8               Z#34 = Utf8               #35 = Utf8               ()V#36 = Utf8               Code#37 = Utf8               LineNumberTable#38 = Utf8               main#39 = Utf8               ([Ljava/lang/String;)V#40 = Utf8               SourceFile#41 = Utf8               ConstantPoolTest.java#42 = NameAndType        #34:#35        // "":()V#43 = NameAndType        #17:#18        // int_num:I#44 = NameAndType        #19:#20        // char_num:C#45 = NameAndType        #21:#22        // short_num:S#46 = NameAndType        #23:#24        // float_num:F#47 = NameAndType        #25:#26        // double_num:D#48 = NameAndType        #27:#28        // byte_num:B#49 = NameAndType        #29:#30        // long_num:J#50 = NameAndType        #32:#33        // boolean_flag:Z#51 = Utf8               org/example/jvm/ConstantPoolTest#52 = Utf8               java/lang/Object
{public org.example.jvm.ConstantPoolTest();descriptor: ()Vflags: ACC_PUBLICCode:stack=3, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."":()V4: aload_05: bipush        1107: putfield      #2                  // Field int_num:I10: aload_011: bipush        9713: putfield      #3                  // Field char_num:C16: aload_017: bipush        12019: putfield      #4                  // Field short_num:S22: aload_023: ldc           #5                  // float 130.0f25: putfield      #6                  // Field float_num:F28: aload_029: ldc2_w        #7                  // double 140.0d32: putfield      #9                  // Field double_num:D35: aload_036: bipush        11138: putfield      #10                 // Field byte_num:B41: aload_042: ldc2_w        #11                 // long 3333l45: putfield      #13                 // Field long_num:J48: aload_049: iconst_1LineNumberTable:line 13: 0line 15: 4line 16: 10line 17: 16line 18: 22line 19: 28line 20: 35line 21: 41line 23: 48public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=0, locals=1, args_size=10: returnLineNumberTable:line 27: 0
}
SourceFile: "ConstantPoolTest.java"
PS E:\VSCODE_FILE\Test\src\main\java\org\example\jvm> javac .\ConstantPoolTest.java          
PS E:\VSCODE_FILE\Test\src\main\java\org\example\jvm> javap -verbose .\ConstantPoolTest.class
Classfile /E:/VSCODE_FILE/Test/src/main/java/org/example/jvm/ConstantPoolTest.classLast modified 2023-3-14; size 710 bytesMD5 checksum 30896b5e6fccdb34ecc7c03e41cfbed5Compiled from "ConstantPoolTest.java"
public class org.example.jvm.ConstantPoolTestminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #17.#43        // java/lang/Object."":()V#2 = Fieldref           #16.#44        // org/example/jvm/ConstantPoolTest.int_num:I#3 = Fieldref           #16.#45        // org/example/jvm/ConstantPoolTest.char_num:C#4 = Fieldref           #16.#46        // org/example/jvm/ConstantPoolTest.short_num:S#5 = Float              130.0f#6 = Fieldref           #16.#47        // org/example/jvm/ConstantPoolTest.float_num:F#7 = Double             140.0d#9 = Fieldref           #16.#48        // org/example/jvm/ConstantPoolTest.double_num:D#10 = Fieldref           #16.#49        // org/example/jvm/ConstantPoolTest.byte_num:B#11 = Long               3333l#13 = Fieldref           #16.#50        // org/example/jvm/ConstantPoolTest.long_num:J#14 = Fieldref           #16.#51        // org/example/jvm/ConstantPoolTest.boolean_flag:Z#15 = String             #52            // ggzx !!!!,这里是我定义的字符串#16 = Class              #53            // org/example/jvm/ConstantPoolTest#17 = Class              #54            // java/lang/Object#18 = Utf8               int_num#19 = Utf8               I#20 = Utf8               char_num#21 = Utf8               C#22 = Utf8               short_num#23 = Utf8               S#24 = Utf8               float_num#25 = Utf8               F#26 = Utf8               double_num#27 = Utf8               D#28 = Utf8               byte_num#29 = Utf8               B#30 = Utf8               long_num#31 = Utf8               J#32 = Utf8               long_delay_num#33 = Utf8               boolean_flag#34 = Utf8               Z#35 = Utf8               #36 = Utf8               ()V#37 = Utf8               Code#38 = Utf8               LineNumberTable#39 = Utf8               main#40 = Utf8               ([Ljava/lang/String;)V#41 = Utf8               SourceFile#42 = Utf8               ConstantPoolTest.java#43 = NameAndType        #35:#36        // "":()V#44 = NameAndType        #18:#19        // int_num:I#45 = NameAndType        #20:#21        // char_num:C#46 = NameAndType        #22:#23        // short_num:S#47 = NameAndType        #24:#25        // float_num:F#48 = NameAndType        #26:#27        // double_num:D#49 = NameAndType        #28:#29        // byte_num:B#50 = NameAndType        #30:#31        // long_num:J#51 = NameAndType        #33:#34        // boolean_flag:Z#52 = Utf8               ggzx#53 = Utf8               org/example/jvm/ConstantPoolTest#54 = Utf8               java/lang/Object
{public org.example.jvm.ConstantPoolTest();descriptor: ()Vflags: ACC_PUBLICCode:stack=3, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."":()V4: aload_05: bipush        1107: putfield      #2                  // Field int_num:I10: aload_011: bipush        9713: putfield      #3                  // Field char_num:C16: aload_017: bipush        12019: putfield      #4                  // Field short_num:S22: aload_023: ldc           #5                  // float 130.0f25: putfield      #6                  // Field float_num:F28: aload_029: ldc2_w        #7                  // double 140.0d32: putfield      #9                  // Field double_num:D35: aload_036: bipush        11138: putfield      #10                 // Field byte_num:B41: aload_042: ldc2_w        #11                 // long 3333l45: putfield      #13                 // Field long_num:J48: aload_049: iconst_150: putfield      #14                 // Field boolean_flag:Z53: returnLineNumberTable:line 13: 0line 15: 4line 16: 10line 17: 16line 18: 22line 19: 28line 20: 35line 21: 41line 23: 48public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=1, locals=2, args_size=10: ldc           #15                 // String ggzx2: astore_13: returnLineNumberTable:line 26: 0line 27: 3
}
SourceFile: "ConstantPoolTest.java"

结论:

  1. final 修饰的 8 种基本类型的值, 会全部进入常量池
  2. 非 final 修饰的, 也包括使用了 static 的情况, 只有 double, float,long 的值会进入常量池
  3. 所有字符串类型字面量 这里在以后的文章中的 StringTable 会讲, 很有趣

先看看如何存储 int 和 float 数据类型的变量

![[Pasted image 20230314134952.png]]

我们只需要了解, 对于这类 int, float,long, double 基本数据类型, 每个数据肯定都需要相同的存储空间.

String 又如何存储呢?

刚才上面我们说到, 对于哪一类固定存储空间的, 很简单. 那么 String 呢?String 需要的空间不一定啊.

这里我们要搞清楚一个点, 就是 String 和字符串在这里的小小区别 ,就是 String 并不是基本数据类型, 字符串是一个常量,String 属于引用, 其引用指向的内容, 是字符串.这里很重要嗷

既然谈到字符串了, 先来看看字符串如何存储的

// 下面的ConstantPool里面的部分 
#15 = String             #52            // ggzx !!!!,这里是我定义的字符串
#52 = Utf8               ggzx// 这里是main方法的字节码
Code:stack=1, locals=2, args_size=10: ldc           #15                 // String ggzx2: astore_13: return

欸, 怎么"定义了"两个 "ggzx"字符串, 但是其实没有哦, 这里的 #15 是啥呢, 是 String 引用, 那后面的 #52 有是啥, 是一个 Utf-8 类型欸, 这里指的就是一个字符串内容.

也就是说,String 是一个引用, 他保存着一个字符串, 所有字符串都是有编号的, String 直接指向字符串就可以了.

现在我们再来看看是 String 如何存储的,
![[Pasted image 20230314135408.png]]

看看这里,String 是一个引用, 他只需要保存目标字符串的序号即可.

在看一个图片:
![[Pasted image 20230314141501.png]]

引用类型如何存储的

经过 String 的分析, 你可能有一些头绪了. 引用类型, 是也给引用指向在堆中分配的实例数据.Class 就是一个文本哇, 哪里有堆?
来看看引用类型的结构:
![[Pasted image 20230314141529.png]]

这个是不是和 String 很像, 保存的依然是序号.
那这个序号存储的是啥呢?

符号引用: 不知道你看见这个的时候, 有没有想到类加载阶段的解析阶段. 对的, 没错, 就是哪个.
符号引用是啥呢:
符号引用本质上就是字符串, 但是这个字符串是具有意义的, 根据这个字符串能找到目标.
比如说类的全限定名: com.ggzx.User, 当然接口也可以.
在类加载的解析阶段: 会把符号引用解析成直接引用
解析动作主要针对于接口字段类方法接口方法,方法类型,因为没有将符号引用替换之前,比如说一个类,一个类的字段,调用的方法,其都是一个字符,而将符号引用解析成直接引用的过程是找到这个方法,这个类,这个属性的一个存储位置的指针。

撰文不易, 期望一个小小的赞.
本文讲的确实不多, 是因为我自己比较喜欢记录自己思考过的东西, 而不是去写一篇"说明书".
下一篇文章仍然会讲述 Class 文件相关的知识

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...