java编程

jvm中class文件结构解析学习

字号+ 作者:风潇潇 来源:原创 2017-05-18 02:51 我要评论( )

好不容易搞懂了class文件格式,今天记录下。jvm是个好东西。厉害

Java的class文件结构解析
u代表一个8位的无符号数,u1代表一个8位的无符号数,u2代表2个8位的无符号数,一次类推
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
1、java魔数、主次版本号

由数据可以看出,此class文件版本为3*16+3=51,对应着jdk的版本为java7
2、常量池,图中红色框都是常量

常量池总结构结构如下:

 
这里根据图列举第一个常量的解析:tag位是0A,转换位10进制是10,对应着CONSTANT_Mehthodref_info 则接下来的4个字节因为是CONSTANT_Class_Info 和CONSTANT_NameAndType 的索引项分别是0009和0016,通过jvm反编译的常量池可知,这方法指的是jvm自己添加的init方法。
         #9 = Class              #31            //  java/lang/Object
#31 = Utf8               java/lang/Object
#22 = NameAndType        #12:#13        //  "<init>":()V
#12 = Utf8               <init>
#13 = Utf8               ()V
 
 
3、Access_flag 、this_class 、super_class、interfaces_count这几个属性

Acess_flag的取值:
ACC_PUBLIC 0x0001 可以被包的类外访问。
ACC_FINAL 0x0010 不允许有子类。
ACC_SUPER 0x0020 当用到 invokespecial 指令时,需要特殊处理③的父类方法。
ACC_INTERFACE 0x0200 标识定义的是接口而不是类。
ACC_ABSTRACT 0x0400 不能被实例化。
ACC_SYNTHETIC 0x1000 标识并非 Java 源码生成的代码。
ACC_ANNOTATION 0x2000 标识注解类型
ACC_ENUM 0x4000 标识枚举类型
4、field_info 结构格式如下
 

其中fields_count这个类只有一个属性。Access_flags为0002。由下可知此属性为private属性。而属性名为常量池name_index(即000A)位置
ACC_PUBLIC 0x0001 public,表示字段可以从任何包访问。
ACC_PRIVATE 0x0002 private,表示字段仅能该类自身调用。
ACC_PROTECTED 0x0004 protected,表示字段可以被子类调用。
ACC_STATIC 0x0008 static,表示静态字段。
ACC_FINAL 0x0010 final, 表示字段定义后值无法修改( JLS §17.5)。
Java 虚拟机规范 — 第 4 章 Class 文件格式
第 109 页 / 共 387 页
ACC_VOLATILE 0x0040 volatile, 表示字段是易变的。
ACC_TRANSIENT 0x0080 transient, 表示字段不会被序列化。
ACC_SYNTHETIC 0x1000 表示字段由编译器自动产生。
ACC_ENUM 0x4000 enum, 表示字段为枚举类型。
 
注意,像这种是可以叠加的,比如如果是public static ,则access_flags应该是0009
 
5、method_info结构如下,以及实际数据如下。methods_count 为 00003 标明此Class有三个方法,包括静态的、以及jvm自己添加的init方法,切其中有一个属性

其中属性结构:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
如下图,对应的数据,这里只有一个属性,那就是叫code属性,常量池索引号为000E位置,对应#15号,即code属性,这个属性里面就有方法的需要执行的字节码等信息

其中具体属性数据如下:

 
属性里面的属性:

对应jvm的如下:
LineNumberTable:
        line 1: 0
        line 3: 4
 
 
 

 
Jvm指令:
 
Classfile /F:/java_bin/MyTest.class
  Last modified 2017-5-17; size 573 bytes
  MD5 checksum 75d8702b3069ee4193618cdcffb4bf1b
  Compiled from "MyTest.java"
public class MyTest
  SourceFile: "MyTest.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Methodref          #9.#22         //  java/lang/Object."<init>":()V
   #2 = String             #23            //  xuzhen
   #3 = Fieldref           #4.#24         //  MyTest.name:Ljava/lang/String;
   #4 = Class              #25            //  MyTest
   #5 = Methodref          #4.#22         //  MyTest."<init>":()V
   #6 = Fieldref           #26.#27        //  java/lang/System.out:Ljava/io/PrintStream;
   #7 = Methodref          #4.#28         //  MyTest.getName:()Ljava/lang/String;
   #8 = Methodref          #29.#30        //  java/io/PrintStream.println:(Ljava/lang/String;)V
   #9 = Class              #31            //  java/lang/Object
  #10 = Utf8               name
  #11 = Utf8               Ljava/lang/String;
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               main
  #17 = Utf8               ([Ljava/lang/String;)V
  #18 = Utf8               getName
  #19 = Utf8               ()Ljava/lang/String;
  #20 = Utf8               SourceFile
  #21 = Utf8               MyTest.java
  #22 = NameAndType        #12:#13        //  "<init>":()V
  #23 = Utf8               xuzhen
  #24 = NameAndType        #10:#11        //  name:Ljava/lang/String;
  #25 = Utf8               MyTest
  #26 = Class              #32            //  java/lang/System
  #27 = NameAndType        #33:#34        //  out:Ljava/io/PrintStream;
  #28 = NameAndType        #18:#19        //  getName:()Ljava/lang/String;
  #29 = Class              #35            //  java/io/PrintStream
  #30 = NameAndType        #36:#37        //  println:(Ljava/lang/String;)V
  #31 = Utf8               java/lang/Object
  #32 = Utf8               java/lang/System
  #33 = Utf8               out
  #34 = Utf8               Ljava/io/PrintStream;
  #35 = Utf8               java/io/PrintStream
  #36 = Utf8               println
  #37 = Utf8               (Ljava/lang/String;)V
{
  private java.lang.String name;
    flags: ACC_PRIVATE
  public MyTest();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 1: 0
      line 3: 4
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0      
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0      
         5: ldc           #2                  // String xuzhen
         7: putfield      #3                  // Field name:Ljava/lang/String;
        10: return       
      LineNumberTable:
        line 1: 0
        line 3: 4
  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    LineNumberTable:
      line 6: 0
      line 7: 8
      line 8: 18
    Code:
      stack=2, locals=2, args_size=1
         0: new           #4                  // class MyTest
         3: dup          
         4: invokespecial #5                  // Method "<init>":()V
         7: astore_1     
         8: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_1      
        12: invokevirtual #7                  // Method getName:()Ljava/lang/String;
        15: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        18: return       
      LineNumberTable:
        line 6: 0
        line 7: 8
        line 8: 18
  public java.lang.String getName();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 11: 0
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0      
         1: getfield      #3                  // Field name:Ljava/lang/String;
         4: areturn      
      LineNumberTable:
        line 11: 0
}

转载请注明出处。

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • Jvm虚拟机学习一些基本概念

    Jvm虚拟机学习一些基本概念

    2017-05-18 11:12

  • java的class文件查看(入门)

    java的class文件查看(入门)

    2016-09-22 16:36

  • java class文件结构

    java class文件结构

    2016-08-10 17:29

  • java 运行参数设置

    java 运行参数设置

    2016-04-18 09:51

网友点评
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)