Java class 文件时对Java程序二进制文件格式的精确定义。
一个class文件只能包含一个类或接口。
Java class文件是8位字节的二进制流。
在Java class文件中,可变长度项的大小和长度位于其实际数据之前。
class文件的基本类型
u1 1byte 无符号类型
u2 2byte 无符号类型
u4 4byte 无符号类型
u8 8byte 无符号类型
=============================================================================================================================
以下是Java源码文件
public classClassTest {final static int constantInt=12;final static String constantString="我很好";static int variableInt=12;static String variableString="我很好";private intvariable;privateString variable2;public static voidmain(String[] args) {
System.out.println("--这是main()方法---");
}public voidsay() {
System.out.println("这是普通方法");
}public ClassTest(intvariable, String variable2) {super();this.variable =variable;this.variable2 =variable2;
}publicClassTest() {
}
View Code
以下是使用uedit 编辑器查看的字节码文件
以下是使用 javap -v ClssTest.class 查看的字节码文件内容
Last modified 2019-7-24; size 924bytes
MD5 checksum be5b20653620d7d2b495a3f99e3fb417
Compiled from"ClassTest.java"
public classClassTest
minor version:0major version:52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Fieldref #34.#35 //java/lang/System.out:Ljava/io/PrintStream;
#2 = String #36 //--这是main()方法---
#3 = Methodref #37.#38 //java/io/PrintStream.println:(Ljava/lang/String;)V
#4 = String #39 //这是普通方法
#5 = Methodref #12.#40 //java/lang/Object."":()V
#6 = Fieldref #11.#41 //ClassTest.variable:I
#7 = Fieldref #11.#42 //ClassTest.variable2:Ljava/lang/String;
#8 = Fieldref #11.#43 //ClassTest.variableInt:I
#9 = String #44 //我很好
#10 = Fieldref #11.#45 //ClassTest.variableString:Ljava/lang/String;
#11 = Class #46 //ClassTest
#12 = Class #47 //java/lang/Object
#13 =Utf8 constantInt
#14 =Utf8 I
#15 =Utf8 ConstantValue
#16 = Integer 12#17 =Utf8 constantString
#18 = Utf8 Ljava/lang/String;
#19 =Utf8 variableInt
#20 =Utf8 variableString
#21 =Utf8 variable
#22 =Utf8 variable2
#23 =Utf8 main
#24 = Utf8 ([Ljava/lang/String;)V
#25 =Utf8 Code
#26 =Utf8 LineNumberTable
#27 =Utf8 say
#28 =Utf8 ()V
#29 = Utf8 #30 = Utf8 (ILjava/lang/String;)V
#31 = Utf8 #32 =Utf8 SourceFile
#33 =Utf8 ClassTest.java
#34 = Class #48 //java/lang/System
#35 = NameAndType #49:#50 //out:Ljava/io/PrintStream;
#36 = Utf8 --这是main()方法---#37 = Class #51 //java/io/PrintStream
#38 = NameAndType #52:#53 //println:(Ljava/lang/String;)V
#39 =Utf8 这是普通方法
#40 = NameAndType #29:#28 //"":()V
#41 = NameAndType #21:#14 //variable:I
#42 = NameAndType #22:#18 //variable2:Ljava/lang/String;
#43 = NameAndType #19:#14 //variableInt:I
#44 =Utf8 我很好
#45 = NameAndType #20:#18 //variableString:Ljava/lang/String;
#46 =Utf8 ClassTest
#47 = Utf8 java/lang/Object
#48 = Utf8 java/lang/System
#49 =Utf8 out
#50 = Utf8 Ljava/io/PrintStream;
#51 = Utf8 java/io/PrintStream
#52 =Utf8 println
#53 = Utf8 (Ljava/lang/String;)V
{static final intconstantInt;
descriptor: I
flags: ACC_STATIC, ACC_FINAL
ConstantValue:int 12
static finaljava.lang.String constantString;
descriptor: Ljava/lang/String;
flags: ACC_STATIC, ACC_FINAL
ConstantValue: String 我很好static intvariableInt;
descriptor: I
flags: ACC_STATICstaticjava.lang.String variableString;
descriptor: Ljava/lang/String;
flags: ACC_STATICpublic static voidmain(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #1 //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #2 //String --这是main()方法---
5: invokevirtual #3 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: returnLineNumberTable:
line11: 0line13: 8
public voidsay();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #1 //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 //String 这是普通方法
5: invokevirtual #3 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: returnLineNumberTable:
line15: 0line16: 8
public ClassTest(int, java.lang.String);
descriptor: (ILjava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_01: invokespecial #5 //Method java/lang/Object."":()V
4: aload_05: iload_16: putfield #6 //Field variable:I
9: aload_010: aload_211: putfield #7 //Field variable2:Ljava/lang/String;
14: returnLineNumberTable:
line18: 0line19: 4line20: 9line21: 14
publicClassTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_01: invokespecial #5 //Method java/lang/Object."":()V
4: returnLineNumberTable:
line22: 0line24: 4
static{};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 12
2: putstatic #8 //Field variableInt:I
5: ldc #9 //String 我很好
7: putstatic #10 //Field variableString:Ljava/lang/String;
10: returnLineNumberTable:
line5: 0line6: 5}
SourceFile:"ClassTest.java"
View Code
简单版本:
minor version: 0 //---主版本号
major version: 52 //---次版本号
flags: ACC_PUBLIC, ACC_SUPER //---类访问标识//--- 常量池
Constant pool:
#1 = Fieldref #34.#35 //java/lang/System.out:Ljava/io/PrintStream;
#2 = String #36 //--这是main()方法---
.......
#52 =Utf8 println
#53 = Utf8 (Ljava/lang/String;)V
{//--- 字段信息
static final intconstantInt;
descriptor: I
flags: ACC_STATIC, ACC_FINAL
ConstantValue:int 12
static intvariableInt;
descriptor: I
flags: ACC_STATIC//---方法信息
public static voidmain(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #1 //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #2 //String --这是main()方法---
5: invokevirtual #3 //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: returnLineNumberTable:
line11: 0line13: 8
publicClassTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_01: invokespecial #5 //Method java/lang/Object."":()V
4: returnLineNumberTable:
line22: 0line24: 4
//-- super()方法
static{};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 12
2: putstatic #8 //Field variableInt:I
5: ldc #9 //String 我很好
7: putstatic #10 //Field variableString:Ljava/lang/String;
10: returnLineNumberTable:
line5: 0line6: 5}
class 文件内容项
magic(魔数) : class文件前四位字节,class文件总是以 0xCAFEBABE 开头,作为class文件标识。
minor_version / major_version 主次版本号,JVM 根据版本号决定如何加载class文件
constant_pool_count / constant_pool :常量池
每一个常量池入口都是从一个标识(长度是一个字节)开始。次标识指明该位置常量的类型。
每一个标志都有一个相对的表,表名就是标志名加上“_info” 即 constant_utf8_info
access_flage : 访问标志,指明class文件定义的是类还是接口,以及类或接口的修饰符。
this_class :就是指向常量池中constant_class_info的索引。
super_class :也是一个指向常量池的索引。
interfaces / fields / methods /attribute :也是指向常量池的索引。
XXX_count :就是对应的数量。