Class文件是以8个字节为单位的二进制流,紧凑排列,中间没有空隙;如果想查看一个Class文件除了通过winHex编译器看到字节码,也可以通过javap -verbose xxx.Class 输出字节码内容,这样看起来比较直观。
版本号之后紧跟的就是常量池入口,可以理解为Class文件之中的资源仓库;
常量池之后紧跟的就是访问标志。主要包括了这个Class是类or接口,是不是public,是不是abstract类型,是不是final类型。
和字段表集合差不多,方法表集合用来描述Class文件中的方法,但是访问标志和属性表集合和字段表集合有所区别;
上述那些表需要携带自己的某些属性,来描述自己的特殊环境信息,比如InnderClasses、LineNumberTable、Code之类的;
Java虚拟机采用面向操作数栈而不是寄存器的架构,字节码指令集是一种指令集架构。放弃了操作数对齐,省略了填充的符号和间隔。
将数据在帧栈中将局部变量表和操作数栈之间来回传输。
1、Java文件:
package com.xxx.ccc;public final class InitConfig {
public static final InitConfig BFCACCOUNT = new InitConfig(0, "aaa", "AAA");
private int mIndex;
private String mData;
private String mDescribe;private InitConfig(int indexFlag, String data, String describe) {
this.mIndex = indexFlag;
this.mData = data;
this.mDescribe = describe;
}public String getmData() {
return this.mData;
}
}
Last modified 2017-7-4; size 1050 bytes
MD5 checksum 2beb0c10f91b793c3570edcf2d1eff78
Compiled from "InitConfig.java"
public final class com.xxx.xxx.InitConfig
minor version: 0 //次版本号
major version: 51 //主版本号
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER //访问标志
Constant pool: //常量池
#1 = Methodref #14.#41 // java/lang/Object."<init>":()V
#2 = Fieldref #5.#42 // com/xxx/xxx/InitConfig.mIndex:I
#6 = Class #46 // com/xxx/xxx/common/constant/ConstData
#7 = String #47 // aaa
#23 = Utf8 <init>
#24 = Utf8 (ILjava/lang/String;Ljava/lang/String;)V
#25 = Utf8 Code
#26 = Utf8 LineNumberTable //Java的源码行号和字节码行号
#27 = Utf8 LocalVariableTable //局部变量表中的变量与Java源码中定义的变量之间的关系
#28 = Utf8 this
#32 = Utf8 getmData
#33 = Utf8 ()Ljava/lang/String;
#37 = Utf8 <clinit>
#38 = Utf8 ()V
#40 = Utf8 InitConfig.java
#41 = NameAndType #23:#38 // "<init>":()V
#45 = Utf8 com/xxx/xxx/InitConfig
#46 = Utf8 com/xxx/xxx/common/constant/ConstData
#53 = NameAndType #17:#16 // SEAACCOUNT:Lcom/xxx/ccc/InitConfig;
#54 = Utf8 java/lang/Objectpublic static final com.xxx.xxx BFCACCOUNT;
descriptor: Lcom/xxx/xxx/InitConfig;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINALpublic java.lang.String getmData();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #3 // Field mData:Ljava/lang/String;
4: areturn
LineNumberTable: //Java的源码行号和字节码行号
line 36: 0
LocalVariableTable: //局部变量表中的变量与Java源码中定义的变量之间的关系
Start Length Slot Name Signature
0 5 0 this Lcom/xxx/xxx/InitConfig; //方法里面默认增加了个this
为什么说一些”非Java"语言也是可以在JVM上跑,这是因为JVM只认识Class文件,所以如果某某语言最终编译出的文件是Class文件,那么对于JVM来说没有什么区别,但是得按照Class文件的结构来,不然也无法正常执行。Class定义了许多特定的基本类型和表结构,通过魔数让JVM认识该文件,版本号保证可以在要求的JDK版本上运行,在常量池中定义好常量,访问标志位确定访问权限。索引集合方便与外界的class保持联系,字段表保存我们定义好的变量,方法表存储方法的信息,属性表存储了上述各种表的一些属性。其中记住slot为局部变量分配内存的最小单位,当程序超出作用域的时候,slot可以被其他替换使用。到这里,仅仅是代码最静态的存储的格式,程序要运行起来。还需要操作指令,也是由字节码存储,包括操作码和操作数。有加载存储、运算、类型转换、同步指令。
说明: 本系列多处摘抄《深入理解Java虚拟机》中内容,主要精简了本书的要点,并叙述自己对本书的理解。本人才疏学浅,文章中有不对的地方,还望批评指教。
小贴士
本文由原作者井方哥独家授权Open软件开发小组发布,著作权归原作者所有。如需转载请联系原作者申请授权。