Java class 文件时对Java程序二进制文件格式的精确定义。
一个class文件只能包含一个类或接口。
Java class文件是8位字节的二进制流。
在Java class文件中,可变长度项的大小和长度位于其实际数据之前。
class文件的基本类型
u1 1byte 无符号类型
u2 2byte 无符号类型
u4 4byte 无符号类型
u8 8byte 无符号类型
=============================================================================================================================
以下是Java源码文件
public class ClassTest { final static int constantInt=12; final static String constantString="我很好"; static int variableInt=12; static String variableString="我很好"; private int variable; private String variable2; public static void main(String[] args) { System.out.println("--这是main()方法---"); } public void say() { System.out.println("这是普通方法"); } public ClassTest(int variable, String variable2) { super(); this.variable = variable; this.variable2 = variable2; } public ClassTest() { }
以下是使用uedit 编辑器查看的字节码文件
以下是使用 javap -v ClssTest.class 查看的字节码文件内容
Last modified 2019-7-24; size 924 bytes MD5 checksum be5b20653620d7d2b495a3f99e3fb417 Compiled from "ClassTest.java" public class ClassTest 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()方法--- #3 = Methodref #37.#38 // java/io/PrintStream.println:(Ljava/lang/String;)V #4 = String #39 // 这是普通方法 #5 = Methodref #12.#40 // java/lang/Object."<init>":()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 <init> #30 = Utf8 (ILjava/lang/String;)V #31 = Utf8 <clinit> #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 // "<init>":()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 int constantInt; descriptor: I flags: ACC_STATIC, ACC_FINAL ConstantValue: int 12 static final java.lang.String constantString; descriptor: Ljava/lang/String; flags: ACC_STATIC, ACC_FINAL ConstantValue: String 我很好 static int variableInt; descriptor: I flags: ACC_STATIC static java.lang.String variableString; descriptor: Ljava/lang/String; flags: ACC_STATIC public static void main(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: return LineNumberTable: line 11: 0 line 13: 8 public void say(); 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: return LineNumberTable: line 15: 0 line 16: 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_0 1: invokespecial #5 // Method java/lang/Object."<init>":()V 4: aload_0 5: iload_1 6: putfield #6 // Field variable:I 9: aload_0 10: aload_2 11: putfield #7 // Field variable2:Ljava/lang/String; 14: return LineNumberTable: line 18: 0 line 19: 4 line 20: 9 line 21: 14 public ClassTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #5 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 22: 0 line 24: 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: return LineNumberTable: line 5: 0 line 6: 5 } SourceFile: "ClassTest.java"
简单版本:
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 int constantInt; descriptor: I flags: ACC_STATIC, ACC_FINAL ConstantValue: int 12 static int variableInt; descriptor: I flags: ACC_STATIC //---方法信息 public static void main(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: return LineNumberTable: line 11: 0 line 13: 8 public ClassTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #5 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 22: 0 line 24: 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: return LineNumberTable: line 5: 0 line 6: 5 }
class 文件内容项
magic(魔数) : class文件前四位字节,class文件总是以 0xCAFEBABE 开头,作为class文件标识。
minor_version / major_version 主次版本号,JVM 根据版本号决定如何加载class文件
constant_pool_count / constant_pool :常量池
每一个常量池入口都是从一个标识(长度是一个字节)开始。次标识指明该位置常量的类型。
每一个标志都有一个相对的表,表名就是标志名加上“_info” 即 constant_utf8_info
常量池具体描述 : https://blog.csdn.net/hxcaifly/article/details/82887552
access_flage : 访问标志,指明class文件定义的是类还是接口,以及类或接口的修饰符。
this_class :就是指向常量池中constant_class_info的索引。
super_class :也是一个指向常量池的索引。
interfaces / fields / methods /attribute :也是指向常量池的索引。
XXX_count :就是对应的数量。