java字节码解析-class文件结构

相信学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; }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值