原文地址:http://blog.csdn.net/wzju64676266/article/details/5874703
相信学java的人都对new Object();创建对象都很熟悉,但想要真正了解原理就没那么容易!以以下例子为例,解释class代码及执行过程,如有错误,还望各位高手多多指教!
帧的创建如下所示:
class文件格式如下:
程序计数器(pc):每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令,对于非Native方法,这个区域记录的是正在执行的VM原语的地址,如果正在执行的是Natvie方法,这个区域则为空(undefined)。
程序计数器 例子和图就拿现成的了,直接引用同事的
- public class Demo {
- public static void foo() {
- int a = 1;
- int b = 2;
- int c = (a + b) * 5;
- }
- }
接下来来看一个例子,源代码如下:
- 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文件生产字节码是怎么样的
执行javac Dog.java文件,生成class文件。然后使用javap -verbose Dog反编译出class代码。
生成如下代码:
- 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文件都有一些常量池信息
- //当线程调用一个方法的时候,jvm会开辟一个帧出来,这个帧包括操作栈、局部变量列表、常量池的引用
- //如下以#开头的表示偏移量编号,相当于id号,接下来解释如下代码的作用
- 如下 #11.#31; 这段代码什么作用呢?很简单,就是表示创建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表示名字和类型 调用构造方法 的Name都是<init>, V表示没有返回值 ,() 括号里面是空的表示没有参数
- //到这里完成Dog
- //
- 如下有 :
- Method //方法
- Field //类名.属性
- class //类型
- Asciz //方法签名
- NameAndType //变量名和类型
- java类型对应的class文件方法签名的标识符:
- invokespecial //调用构造方法、父类方法
- invokevirtual //调用普通方法(非构造方法、static方法)
- invokestatic //调用static方法
- Ljava/lang/String;; //这表示String类型,这里要全路径,java/lang/String;;前面的L表示非java八大基本类型
- void V
- int char byte short long float double 都是类型第一个字母(大写)
- boolean 比较特别,用J表示 ,因为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 解释:调用println(int value), V表示返回值是void
- const #6 = class #38; // Dog
- const #7 = Method #6.#31; // Dog."<init>":()V 解释:初始化Dog,调用构造函数,"<init>"是初始化标识符, V表示返回值是void
- const #8 = Method #6.#39; // Dog.getValue:(I)V 解释:调用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表示方法内局部变量个数,该例中是1,有些人疑惑的是Dog()中明明没有参数啊,应该是0啊!
- //当线程调用一个方法的时候,jvm会开辟一个帧出来,这个帧包括操作栈、局部变量列表、常量池的引用
- //非static方法,在调用的时候都会给方法默认加上一个当前对象(this)类型的参数,不需要在方法中定义,
- //这个时候局部变量列表中index为0的位置保存的是this,其他索引号按变量定义顺序累加
- //static方法不依赖对象,所以不用传this
- //Args_size表示参数个数,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 //调用构造方法
- 4: return
- LineNumberTable: //见如上的class文件结构图
- line 6: 0
- line 7: 4
- LocalVariableTable: //见如上的class文件结构图
- Start Length Slot Name Signature
- 0 5 0 this LDog;
- //这个构造方法与上个构造方法也是同理,只是多少个String参数和 给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;表示对常量池的引用,创建一个类,必须先初始化父类,创建Dog之前创建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
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this LDog;
- 0 10 1 name Ljava/lang/String;
- 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
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this LDog;
- 0 15 1 name Ljava/lang/String;
- 0 15 2 age I
- //这里的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
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 j I
- 2 8 1 i I
- 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
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this LDog;
- 0 10 1 j I
- 2 8 2 i I
- public static void main(java.lang.String[]);
- Code:
- Stack=2, Locals=2, Args_size=1
- 0: new #6; //class Dog 解释:创建Dog
- 3: dup //复制引用到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行之间如果发生Exception异常就goto到15处
- LineNumberTable:
- line 32: 0
- line 35: 12
- line 33: 15
- line 34: 16
- line 36: 20
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 21 0 args [Ljava/lang/String;
- 16 4 1 e Ljava/lang/Exception;
- }