深入JVM之 class文件解析

我们知道.java文件要转化成程序运行要经过一系列过程的,大体:javac(前端编译器)将.java文件编译成class文件 --> JIT(后端编译器/即时编译器)将.class文件实时将.class解释翻译成机器码,供计算机识别。
JIT的解释过程有个叫热点代码的东西,类似缓存,它会将使用次数较多的代码提前编译好,提高效率。
下面进入重点,这个随着java语言一起诞生,又随着JVM一同壮大的class文件究竟是怎么工作的?它的内部又包含哪些元素?
class文件,示例:

cafe babe 0000 0034 0021 0a00 0400 1907
001a 0a00 1b00 1c07 001d 0100 063c 696e
6974 3e01 0003 2829 5601 0004 436f 6465
0100 0f4c 696e 654e 756d 6265 7254 6162
6c65 0100 124c 6f63 616c 5661 7269 6162……
  1. magic number
    class文件打开,如上,入眼是一堆整齐的十六进制数字,在文件开头的四个字节,也就是 cafebabe是java文件的magic number,用于标识这是一个合法的class文件。
  2. 版本号
    紧接着magic number的两个字节代表次版本号,可以看到这里的示例是0000,因为从JAVA8开始,版本号只采用主版本,次版本号暂时停用。
    次版本号之后的两个字节代表主版本号。高版本的JDK可以向下兼容以前版本的Class文件,但是无法运行以后版本的Class文件。
  3. 常量池。
    没错,就是那个运行时常量池年少时的模样,它存储了这个java类主要的数据,class文件中其他部分的内容大多都是指向这里的引用。它是一个表结构。
    在主版本号的两个字节之后,是常量池的入口,这个入口是一个两个字节的无符号数,constatn_pool_count用来代表整个常量池的大小。(因为常量池的大小是不定量,随类信息多少变化)。
    常量池主要存储两大类数据:字面量和字符引用。字面量主要是文本字符串、final常量,字符引用则是一个‘字符串表示的堆某个类/方法的引用’,会在类加载的解析阶段被置换为直接引用。
    常量池里面还有很多信息,如常量池中数据类型在JDK1.7时有是一种,有表示int、double、long的,也有表示字符串的,也有CONSTANT_Class_info类型来表示类的全限定名等的类型。
    常量池类型表
  4. 访问标识
    常量池之后的两个字节,用于标识该类的访问限定。比如:这是类还是接口,这是不是抽象类,是public还是private、是不是JVM自动生成的类、这是不是注解/枚举类等等。
    访问标识表
  5. 类索引、父类索引、接口索引
    访问标识之后的两位,是一个常量池的索引下标,到常量池取出来的值是类本身的全限定类名。
    再之后的两位,同样是全限定类名,只不过是父类的全限定类名。
    再之后的两位,是接口的count,这个count表示该类实现了几个接口。这两位之后的动态集合则是具体的接口全限定类名所对应的常量池索引下标。
  6. 字段表
    接口索引之后,是字段表,字段表用于描述接口或者类中声明的变量,包括类级变量和实例级变量(是否是static),但不包括在方法内部声明的局部变量。
  7. 方法表
    方法表同字段表,用于描述方法的集合。
  8. 属性表
    在Class文件、字段表和方法表都可以携带自己的属性信息,这个信息用属性表进行描述,用于描述某些场景专有的信息。
    属性表示意表
发布了88 篇原创文章 · 获赞 28 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_35946969/article/details/104867718