爱程序网

读《深入理解Java虚拟机》有感——第一部分:Class文件的结构

来源: 阅读:

1.产生

         源码(.java文件)——>编译器(如:javac)——>字节码(.class文件)——>虚拟机(如:HotSpot)执行

 

2.Class文件

           1)构成:

                    魔数、版本号、常量池、访问标志、索引、字段表集合、方法表集合、Signature属性表、SourseFile属性表

           2)例子:

                    [1] .java文件

                              桌面/test/test/Father.java、桌面/test/test/Father_interface.java、桌面/test/Son.java  ;                     

                    [2]编译出.class文件

                               cd  桌面/test;  

                                    桌面/test>javac  Son.java;

                    [3]查看.class文件

                                    桌面/test>javap -verbose  Son;

 

Classfile /C:/Users/Administrator/Desktop/test/Son.class
  Last modified 2016-4-11; size 1005 bytes
  MD5 checksum 7d138d76267a6bb372eba05296e2c932魔数
  Compiled from "Son.java"
public class test.Son extends test.Father implements test.Father_interface索引1类索引、2父类索引、3接口索引,指向常量池
  SourceFile: "Son.java" 源码属性表<源码名称,指向常量池>
  minor version: 0
  major version: 51主板本号
  flags: ACC_PUBLIC, ACC_SUPER访问标志<当前类>
Constant pool:常量池
一、符号引用{
#
1 = Methodref #16.#33 // test/Father."<init>":()V #2 = Fieldref #15.#34 // test/Son.sId_literal:I 《字段》符号引用 #3 = Fieldref #35.#36 // java/lang/System.out:Ljava/io/PrintStream; #4 = Class #37 // java/lang/StringBuilder 类/接口》符号引用 #5 = Methodref #4.#33 // java/lang/StringBuilder."<init>":()V 《类方法》符号引 #6 = String #38 // statical_sId = 《字面量——静态字段》符号引用 #7 = Methodref #4.#39 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Strin gBuilder; #8 = Fieldref #15.#40 // test/Son.statical_sId:I #9 = Methodref #4.#41 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; #10 = Methodref #4.#42 // java/lang/StringBuilder.toString:()Ljava/lang/String; #11 = Methodref #43.#44 // java/io/PrintStream.println:(Ljava/lang/String;)V #12 = String #45 // Son实例构造器! 《字面量——System.out的字符串》符号引用 #13 = String #46 // hello!this is son! #14 = String #47 // Son类构造器<clinit>执行! #15 = Class #48 // test/Son 1 #16 = Class #49 // test/Father 2 #17 = Class #50 // test/Father_interface 3


二、常量类型{
#18 = Utf8 final_sId UTF-8编码的字符串 #19 = Utf8 I #20 = Utf8 ConstantValue #21 = Integer 123 整型字面量 #22 = Utf8 statical_sId #23 = Utf8 sId_literal #24 = Utf8 sId_nonLiteral #25 = Utf8 <init> #26 = Utf8 ()V /**返回类型*/ #27 = Utf8 Code #28 = Utf8 LineNumberTable #29 = Utf8 sayHello #30 = Utf8 <clinit> #31 = Utf8 SourceFile #32 = Utf8 Son.java


三、符号引用、数据{
#
33 = NameAndType #25:#26 // "<init>":()V 《字段/方法部分》符号引用 #34 = NameAndType #23:#19 // sId_literal:I #35 = Class #51 // java/lang/System #36 = NameAndType #52:#53 // out:Ljava/io/PrintStream; #37 = Utf8 java/lang/StringBuilder #38 = Utf8 statical_sId = #39 = NameAndType #54:#55 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #40 = NameAndType #22:#19 // statical_sId:I #41 = NameAndType #54:#56 // append:(I)Ljava/lang/StringBuilder; #42 = NameAndType #57:#58 // toString:()Ljava/lang/String; #43 = Class #59 // java/io/PrintStream #44 = NameAndType #60:#61 // println:(Ljava/lang/String;)V #45 = Utf8 Son实例构造器! }符号引用 #46 = Utf8 hello!this is son! #47 = Utf8 Son类构造器<clinit>执行! #48 = Utf8 test/Son #49 = Utf8 test/Father #50 = Utf8 test/Father_interface #51 = Utf8 java/lang/System #52 = Utf8 out #53 = Utf8 Ljava/io/PrintStream; #54 = Utf8 append #55 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #56 = Utf8 (I)Ljava/lang/StringBuilder; #57 = Utf8 toString #58 = Utf8 ()Ljava/lang/String; #59 = Utf8 java/io/PrintStream #60 = Utf8 println #61 = Utf8 (Ljava/lang/String;)V { public test.Son();方法表——实例构造器 flags: ACC_PUBLIC Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method test/Father."<init>":()V 4: aload_0 5: bipush 123 7: putfield #2 // Field sId_literal:I 10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 13: new #4 // class java/lang/StringBuilder 16: dup 17: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 20: ldc #6 // String statical_sId = 22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; 25: getstatic #8 // Field statical_sId:I 28: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilde r; 31: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 37: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 40: ldc #12 // String Son实例构造器! 42: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 45: sipush 333 48: putstatic #8 // Field statical_sId:I 51: return LineNumberTable: line 15: 0 line 7: 4 line 16: 10 line 17: 37 line 18: 45 line 19: 51 public void sayHello();方法表——sayHello() flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #13 // String hello!this is son! 5: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 21: 0 line 22: 8 static {};方法表——类构造器(静态代码块) flags: ACC_STATIC Code: stack=3, locals=0, args_size=0 0: bipush 123 2: putstatic #8 // Field statical_sId:I 5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 8: new #4 // class java/lang/StringBuilder 11: dup 12: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 15: ldc #6 // String statical_sId = 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; 20: getstatic #8 // Field statical_sId:I 23: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilde r; 26: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 32: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 35: ldc #14 // String Son类构造器<clinit>执行! 37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 40: return LineNumberTable: line 6: 0 line 11: 5 line 12: 32 line 13: 40 }

 

 

 

          3.分析         

魔数 版本号 常量池   访问标志 索引 字段表集合                                                                           

因为后缀名是可以改的,所以

用它来确定真的是.class文件

44=JDK1.0

45=jdk1.1

....

字面量

基本类型数据值        

<int、double等>   

     

符号引用

<指向UTF-8字符串>          

记录类信息

访问标志

全限定名             

记录方

 简单名称

返回类型

参数列表 

记录成员属性

简单名称

访问标志

返回类型

 

 

 

 

 

 

 

 

本类索引

继承父类索引

实现接口索引

<指向”常量池“符号引用, 记录类信息>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 每张表:           

        访问标志      

 //指向常量池-符号引用-成员

     名称

        描述            返回类型

//指向常量池-符号引用-成员

        附加属性表

           ————ConstantValue表

 

静态成员才有此属性表,如果被final修饰,
就直接把取值(常量池-字面量)写到表中

 

          ————Signature表    

                        //记录泛型信息

 

 

 

 

 

 

 

 

 

 

 

方法表集合

 

     Signature表

SourseFile属性表                                                         

每张表:

            访问标志

 //指向常量池-符号引用-方法

            名称

            描述          

       返回类型、参数列表

//指向常量池-符号引 用-方法

      附加属性表                     

         ————Code表     

   

 虚拟机字节码指令     
(方法内容,抽象方
法无此属性表)

         ————Linumber表

         ————局部变量表     

         ————异常表  

         ————Signature表     

记录泛型信息

  

       记录本类泛型信息

表1

    <本类>

     对应源码文件名称索引                  

 

表2:

    <内部类>

    对应源码文件名称索引

 

....

 

 

 

 

    

 

       

 

          4.相关术语

                   1)特征签名

                             -方法表中所有“参数-描述”的集合,指向常量池的符号引用   

                   2)元数据

                             -方法、字段、类和包的描述信息(即字节码中非虚拟机字节码指令部分)

                   3)<client>()方法

                             ·定义:

                            -即“类构造器”,是由编译器自动收集类中类变量的赋值和静态语句块中语句合并产生,在编译过程中,由编译器将该方法的bit流写入.Class文件。

                             ·例子:

                            -收集“类变量的赋值”

                                      Person.java文件:static int i =20;——————>Person.Class文件: static Person{ int i =20;}

                            -收集“静态语句块中语句”

                                      Person.java文件:static {Person.i =50;}——————>Person.Class文件: static Person{ int i =20; i =50;}

                             ·性质:

                            -按在.java源文件中出现的顺序,依次进行收集;

                            -“类构造器”并不是必须被产生的,因为一个类或接口可以没有静态语句块和类变量的赋值操作;

                            -接口也中可以有“类构造器”,因为从语法上,虽然接口中不能含static{}静态代码块,但是可以含“类变量的赋值”;

                              

 

 

 

关于爱程序网 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助