class文件格式如下:
- 相信學(xué)java的人都對new Object();創(chuàng)建對象都很熟悉,但想要真正了解原理就沒那么容易!以以下例子為例,解釋class代碼及執(zhí)行過程,如有錯誤,還望各位高手多多指教!
- public class Dog {
- public String name;
- public int age;
- public Dog() {
- }
- public Dog(String name)
- {
- this.name = name;
- }
- public Dog(String name, int age)
- {
- this.name = name;
- this.age = age;
- }
- public static void getStaticValue(int j)
- {
- int i=j;
- System.out.println(i);
- }
- public void getValue(int j)
- {
- int i=j;
- System.out.println(i);
- }
- public static void main(String[] args) {
- try {
- new Dog().getValue(10);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- 如上代碼很簡單,main方法加上try catch只是為了 讓大家看一下java文件生產(chǎn)字節(jié)碼是怎么樣的
- 執(zhí)行javac Dog.java文件,生成class文件。然后使用javap -verbose Dog反編譯出class代碼。
- 生成如下代碼:
- view plaincopy to clipboardprint?
- Compiled from "Dog.java"
- public class Dog extends java.lang.Object
- SourceFile: "Dog.java"
- minor version: 0 // minor version: major version:這兩個是表示class文件的版本號,
- major version: 50 //詳細見http://blog.csdn.net/xiaxiaorui2003/archive/2009/07/07/4327029.aspx這位兄弟的blog
- Constant pool: //常量池,如下以const開頭的都是常量池信息,每個class文件都有一些常量池信息
- //當(dāng)線程調(diào)用一個方法的時候,jvm會開辟一個幀出來,這個幀包括操作棧、局部變量列表、常量池的引用
- //如下以#開頭的表示偏移量編號,相當(dāng)于id號,接下來解釋如下代碼的作用
- 如下 #11.#31; 這段代碼什么作用呢?很簡單,就是表示創(chuàng)建Object對象。
- 首先來看.號左邊的#11,找到常量池中#11,跳到const #11 = class #42; // java/lang/Object
- 這個表示是一個Object類型,class后面的 #42;表示接下來要跳到常量池中#42
- 找到const #42 = Asciz java/lang/Object; 表示生成Object類型
- 接下來看.號右邊的#31。
- const #31 = NameAndType #16:#17; //解釋:這里指定到#16 #17
- const #16 = Asciz <init>;
- const #17 = Asciz ()V; //解釋:到這里完成初始化工作
- //NameAndType表示名字和類型 調(diào)用構(gòu)造方法 的Name都是<init>, V表示沒有返回值 ,() 括號里面是空的表示沒有參數(shù)
- //到這里完成Dog
- //
- 如下有 :
- Method //方法
- Field //類名.屬性
- class //類型
- Asciz //方法簽名
- NameAndType //變量名和類型
- java類型對應(yīng)的class文件方法簽名的標識符:
- invokespecial //調(diào)用構(gòu)造方法、父類方法
- invokevirtual //調(diào)用普通方法(非構(gòu)造方法、static方法)
- invokestatic //調(diào)用static方法
- Ljava/lang/String;; //這表示String類型,這里要全路徑,java/lang/String;;前面的L表示非java八大基本類型
- void V
- int char byte short long float double 都是類型第一個字母(大寫)
- boolean 比較特別,用Z表示 ,因為B被byte給占用了
- const #1 = Method #11.#31; // java/lang/Object."<init>":()V 解釋:初始化Object
- const #2 = Field #6.#32; // Dog.name:Ljava/lang/String; Dog類中定義的String name
- const #3 = Field #6.#33; // Dog.age:I Dog類中定義的int age
- const #4 = Field #34.#35; // java/lang/System.out:Ljava/io/PrintStream;
- const #5 = Method #36.#37; // java/io/PrintStream.println:(I)V 解釋:調(diào)用println(int value), V表示返回值是void
- const #6 = class #38; // Dog
- const #7 = Method #6.#31; // Dog."<init>":()V 解釋:初始化Dog,調(diào)用構(gòu)造函數(shù),"<init>"是初始化標識符, V表示返回值是void
- const #8 = Method #6.#39; // Dog.getValue:(I)V 解釋:調(diào)用getValue(int j)方法, V表示返回值是void
- const #9 = class #40; // java/lang/Exception
- const #10 = Method #9.#41; // java/lang/Exception.printStackTrace:()V
- const #11 = class #42; // java/lang/Object
- const #12 = Asciz name;
- const #13 = Asciz Ljava/lang/String;;
- const #14 = Asciz age;
- const #15 = Asciz I;
- const #16 = Asciz <init>;
- const #17 = Asciz ()V;
- const #18 = Asciz Code;
- const #19 = Asciz LineNumberTable;
- const #20 = Asciz (Ljava/lang/String;)V;
- const #21 = Asciz (Ljava/lang/String;I)V;
- const #22 = Asciz getStaticValue;
- const #23 = Asciz (I)V;
- const #24 = Asciz getValue;
- const #25 = Asciz main;
- const #26 = Asciz ([Ljava/lang/String;)V;
- const #27 = Asciz StackMapTable;
- const #28 = class #40; // java/lang/Exception
- const #29 = Asciz SourceFile;
- const #30 = Asciz Dog.java;
- const #31 = NameAndType #16:#17;// "<init>":()V
- const #32 = NameAndType #12:#13;// name:Ljava/lang/String;
- const #33 = NameAndType #14:#15;// age:I
- const #34 = class #43; // java/lang/System
- const #35 = NameAndType #44:#45;// out:Ljava/io/PrintStream;
- const #36 = class #46; // java/io/PrintStream
- const #37 = NameAndType #47:#23;// println:(I)V
- const #38 = Asciz Dog;
- const #39 = NameAndType #24:#23;// getValue:(I)V
- const #40 = Asciz java/lang/Exception;
- const #41 = NameAndType #48:#17;// printStackTrace:()V
- const #42 = Asciz java/lang/Object;
- const #43 = Asciz java/lang/System;
- const #44 = Asciz out;
- const #45 = Asciz Ljava/io/PrintStream;;
- const #46 = Asciz java/io/PrintStream;
- const #47 = Asciz println;
- const #48 = Asciz printStackTrace;
- {
- public java.lang.String name;
- public int age;
- //如下的Locals表示方法內(nèi)局部變量個數(shù),該例中是1,有些人疑惑的是Dog()中明明沒有參數(shù)啊,應(yīng)該是0啊!
- //當(dāng)線程調(diào)用一個方法的時候,jvm會開辟一個幀出來,這個幀包括操作棧、局部變量列表、常量池的引用
- //非static方法,在調(diào)用的時候都會給方法默認加上一個當(dāng)前對象(this)類型的參數(shù),不需要在方法中定義,
- //這個時候局部變量列表中index為0的位置保存的是this,其他索引號按變量定義順序累加
- //static方法不依賴對象,所以不用傳this
- //Args_size表示參數(shù)個數(shù),public Dog();會傳一個this進去,所以value是1
- public Dog();
- Code:
- Stack=1, Locals=1, Args_size=1
- 0: aload_0 //加載局部變量表index為0的變量,在這里是this
- 1: invokespecial #1; //Method java/lang/Object."<init>":()V //調(diào)用構(gòu)造方法
- 4: return
- LineNumberTable:
- line 6: 0
- line 7: 4
- //這個構(gòu)造方法與上個構(gòu)造方法也是同理,只是多少個String參數(shù)和 給name賦值
- public Dog(java.lang.String);
- Code:
- Stack=2, Locals=2, Args_size=2
- 0: aload_0
- 1: invokespecial #1; //Method java/lang/Object."<init>":()V
- //這里的#1;表示對常量池的引用,創(chuàng)建一個類,必須先初始化父類,創(chuàng)建Dog之前創(chuàng)建Object
- 4: aload_0 //加載局部變量表index為0的變量,在這里是this
- 5: aload_1 //加載局部變量表index為1的變量,在這里是String name局部變量
- 6: putfield #2; //Field name:Ljava/lang/String; 賦值操作
- 9: return
- LineNumberTable:
- line 10: 0
- line 11: 4
- line 12: 9
- public Dog(java.lang.String, int);
- Code:
- Stack=2, Locals=3, Args_size=3
- 0: aload_0
- 1: invokespecial #1; //Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: aload_1
- 6: putfield #2; //Field name:Ljava/lang/String;
- 9: aload_0
- 10: iload_2
- 11: putfield #3; //Field age:I
- 14: return
- LineNumberTable:
- line 15: 0
- line 16: 4
- line 17: 9
- line 18: 14
- //這里的Args_size=1,是因為是static方法,不會傳進this
- public static void getStaticValue(int);
- Code:
- Stack=2, Locals=2, Args_size=1
- 0: iload_0
- 1: istore_1 //istore_1其實是是有兩部分組成,i表示int類型 ,1表示局部變量表中index為1。那合起來就是存儲在局部變量表中,index為1的位置
- 2: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream; //引用常量池 #4;
- 5: iload_1
- 6: invokevirtual #5; //Method java/io/PrintStream.println:(I)V //引用常量池 #5;
- 9: return
- LineNumberTable:
- line 21: 0
- line 22: 2
- line 23: 9
- public void getValue(int);
- Code:
- Stack=2, Locals=3, Args_size=2
- 0: iload_1
- 1: istore_2
- 2: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
- 5: iload_2
- 6: invokevirtual #5; //Method java/io/PrintStream.println:(I)V
- 9: return
- LineNumberTable:
- line 26: 0
- line 27: 2
- line 28: 9
- public static void main(java.lang.String[]);
- Code:
- Stack=2, Locals=2, Args_size=1
- 0: new #6; //class Dog 解釋:創(chuàng)建Dog
- 3: dup //復(fù)制引用到stack(棧)
- 4: invokespecial #7; //Method "<init>":()V
- 7: bipush 10 //壓入一個常量10
- 9: invokevirtual #8; //Method getValue:(I)V
- 12: goto 20
- 15: astore_1
- 16: aload_1
- 17: invokevirtual #10; //Method java/lang/Exception.printStackTrace:()V
- 20: return
- Exception table:
- from to target type
- 0 12 15 Class java/lang/Exception //表示上面代碼從1到12行之間如果發(fā)生Exception異常就goto到15處
- LineNumberTable:
- line 32: 0
- line 35: 12
- line 33: 15
- line 34: 16
- line 36: 20
- //如下這塊我不太理解什么意思,加了try catch之后才出現(xiàn)這個的,還有如上的 Stack= ,
- //這個不知道是什么意思,暫沒有領(lǐng)悟 ,望高手指導(dǎo)
- StackMapTable: number_of_entries = 2
- frame_type = 79 /* same_locals_1_stack_item */
- stack = [ class java/lang/Exception ]
- frame_type = 4 /* same */
- }