字节码Class文件解读

一、前言
刚开始学习Java的时候老师告诉我们Java是跨平台语言,一次编译到处运行,那么在Java编译过程中做了什么事情,而虚拟机又是怎么初始化和创建对象的,这里对我知道的做一个记录和梳理,如有理解错误,欢迎评论指出!

要将编写的Java源码要运行起来,首先要经过Java编译器编译。将原来的.java文件经过编译器编译转换成.class字节码文件。编译器的存在主要就是编译不同的源文件,将其转换成能在Java虚拟机上运行的.class文件,不同的语言有不同的编译器,同是转换成能在虚拟机上运行的.class文件。

生成的.class文件为后面的虚拟机加载提供很多前期基础,首先知道虚拟机的加载类过程是动态加载的,也就是在使用到当前类或接口的时候再进行加载。加载的时候需要获取到当前类的符号引用,根据符号引用在创建时或运行时解析、翻译到具体的内存地址中去,也就是为对象分配具体内存地址。
符号引用来源于常量池,这里的常量池可以理解为Class文件中的资源仓库。常量池中主要存放两大类常量:字面量和符号引用,字面量比较接近Java语言层面的常量概念,而符号引用接近于Java语言层面的常量概念,主要包含3类常量

  1. 类和接口的全限定名
  2. 字段的名称和描述符
  3. 方法的名称和描述符
    下面的 #1 = Class #2 // com/app/MainAction 就是该类的全限定名,在对象创建的时候比如遇到New关键字,JVM首先对符号引用进行解析,这里就会用到全限定名。如果找不到对应的符号引用,那么这个类就还没有加载,因此jvm就会进行加载过程。当在运行时解析完符号引用后,JVM就会在堆中为对象分配内存。
    对于编译器编译后的.class文件使用javap 工具能看到相应的反汇编结果

但在介绍反汇编结果前首先说一下Class的整个文件结构,在Class文件结构中,总共有7类数据,分别代表着类的不同信息

  • 魔数与Class文件的版本:用来确定这个文件是否为一个能被虚拟机接受的Class文件
  • 常量池:它是Class文件结构中与其他项目关联最对的数据类型,主要包含的就是字面量和符号引用
  • 访问标志:指明当前类是接口还是类,是否定义为public类型,是或定义为abstract类型,如果是类是否定义为final
  • 类索引、父类索引与接口索引集合:类索引指明当前类的全限定名,父类索引指当前类继承的父类全限定名,接口索引集合表明当前类所实现的接口集合
  • 字段表集合:用于描述接口和类中声明的变量,字段包括类级变量以及实例变量,但不包括在方法里面声明的局部变量,字段表和方法表采用同样的数据结构,依次包括访问标志,名称索引,描述符索引,属性表集合。
  • 方法表集合:结构方式与字段表一样,方法中的java代码在编译成字节码后,存放在方法属性表集合中名为“Code”的属性里。
  • 属性表集合 : 1、Code 属性 2、Exceptions属性 3、LineNumberTable属性 4、LocalVariableTable属性 5 SourceFile属性 6 ConstantValue 属性7InnerClasses属性 8、DepreCated以及Synthetic属性 9 StackMapTable属性 10 Signature属性 11BootstrapMethods属性

其中Code:属性用于存放Java方法中的字节码,Exceptions属性将类中可能抛出的异常进行列举,对于LocalVariableTable:属性则是栈帧中局部变量表中的变量和java源码中的变量间的关系
在这里插入图片描述
SourceFile:用于记录生成这个Class文件的源码名称;ConstantValue属性通知通知虚拟机自动为静态变量赋值,对于static 修饰的变量但不为基础数据类型或者是java.lang.String,会在类构造器方法初始化;而使用了final和static修饰的常量并且是基础数据类型或者是java.lang.String则使用ConstantValue属性初始化,对于非static的变量则在实例构造器中初始化
InnerClasses:用于记录内部和宿主之间的关系,如果定义了内部类就有这个属性
DepreCated以及Synthetic:这两个都是boolean属性,表示有和没有,DepreCated属性用于表示方法和类被弃推荐不再使用

下面是使用javap工具反编译出来的文件,用于分析生成的.Class文件

public class MainAction {
public static void main(String[] args) {
		OtherAction othre = new OtherAction();
		othre.fun();
	}
}

public class com.app.MainAction
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // com/app/MainAction
   #2 = Utf8               com/app/MainAction
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/app/MainAction;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Class              #17            // com/app/OtherAction
  #17 = Utf8               com/app/OtherAction
  #18 = Methodref          #16.#9         // com/app/OtherAction."<init>":()V
  #19 = Methodref          #16.#20        // com/app/OtherAction.fun:()V
  #20 = NameAndType        #21:#6         // fun:()V
  #21 = Utf8               fun
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               othre
  #25 = Utf8               Lcom/app/OtherAction;
  #26 = Utf8               SourceFile
  #27 = Utf8               MainAction.java
{
  public com.app.MainAction();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/app/MainAction;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #16                 // class com/app/OtherAction
         3: dup
         4: invokespecial #18                 // Method com/app/OtherAction."<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #19                 // Method com/app/OtherAction.fun:()V
        12: return
      LineNumberTable:
        line 6: 0
        line 7: 8
        line 8: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  args   [Ljava/lang/String;
            8       5     1 othre   Lcom/app/OtherAction;
}
public class OtherAction {
	static int age = 1;
	int age1 = 2;
	static {
		System.out.println("这是静态代码块");
	}
	{
		System.out.println("这是普通代码块" + age1);
	}

public OtherAction() {
		System.out.println("这是构造方法");
	}
	public static void show() {
		System.out.println("这是静态方法");
	}
		public void fun() {
		System.out.println("这是普通方法");
	}
	}
public class com.app.OtherAction
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // com/app/OtherAction
   #2 = Utf8               com/app/OtherAction
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               age
   #6 = Utf8               I
   #7 = Utf8               age1
   #8 = Utf8               <clinit>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Fieldref           #1.#12         // com/app/OtherAction.age:I
  #12 = NameAndType        #5:#6          // age:I
  #13 = Fieldref           #14.#16        // java/lang/System.out:Ljava/io/PrintStream;
  #14 = Class              #15            // java/lang/System
  #15 = Utf8               java/lang/System
  #16 = NameAndType        #17:#18        // out:Ljava/io/PrintStream;
  #17 = Utf8               out
  #18 = Utf8               Ljava/io/PrintStream;
  #19 = String             #20            // 这是静态代码块
  #20 = Utf8               这是静态代码块
  #21 = Methodref          #22.#24        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #22 = Class              #23            // java/io/PrintStream
  #23 = Utf8               java/io/PrintStream
  #24 = NameAndType        #25:#26        // println:(Ljava/lang/String;)V
  #25 = Utf8               println
  #26 = Utf8               (Ljava/lang/String;)V
  #27 = Utf8               LineNumberTable
  #28 = Utf8               LocalVariableTable
  #29 = Utf8               <init>
  #30 = Methodref          #3.#31         // java/lang/Object."<init>":()V
  #31 = NameAndType        #29:#9         // "<init>":()V
  #32 = Fieldref           #1.#33         // com/app/OtherAction.age1:I
  #33 = NameAndType        #7:#6          // age1:I
  #34 = Class              #35            // java/lang/StringBuilder
  #35 = Utf8               java/lang/StringBuilder
  #36 = String             #37            // 这是普通代码块
  #37 = Utf8               这是普通代码块
  #38 = Methodref          #34.#39        // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  #39 = NameAndType        #29:#26        // "<init>":(Ljava/lang/String;)V
  #40 = Methodref          #34.#41        // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #41 = NameAndType        #42:#43        // append:(I)Ljava/lang/StringBuilder;
  #42 = Utf8               append
  #43 = Utf8               (I)Ljava/lang/StringBuilder;
  #44 = Methodref          #34.#45        // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #45 = NameAndType        #46:#47        // toString:()Ljava/lang/String;
  #46 = Utf8               toString
  #47 = Utf8               ()Ljava/lang/String;
  #48 = String             #49            // 这是构造方法
  #49 = Utf8               这是构造方法
  #50 = Utf8               this
  #51 = Utf8               Lcom/app/OtherAction;
  #52 = Utf8               show
  #53 = String             #54            // 这是静态方法
  #54 = Utf8               这是静态方法
  #55 = Utf8               fun
  #56 = String             #57            // 这是普通方法
  #57 = Utf8               这是普通方法
  #58 = Utf8               SourceFile
  #59 = Utf8               OtherAction.java
{
  static int age;
    descriptor: I
    flags: ACC_STATIC

  int age1;
    descriptor: I
    flags:

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: iconst_1
         1: putstatic     #11                 // Field age:I
         4: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #19                 // String 这是静态代码块
         9: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: return
      LineNumberTable:
        line 5: 0
        line 9: 4
        line 10: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

  public com.app.OtherAction();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=1, args_size=1
         0: aload_0
         1: invokespecial #30                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_2
         6: putfield      #32                 // Field age1:I
         9: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
        12: new           #34                 // class java/lang/StringBuilder
        15: dup
        16: ldc           #36                 // String 这是普通代码块
        18: invokespecial #38                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
        21: aload_0
        22: getfield      #32                 // Field age1:I
        25: invokevirtual #40                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        28: invokevirtual #44                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        31: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        34: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
        37: ldc           #48                 // String 这是构造方法
        39: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        42: return
      LineNumberTable:
        line 16: 0
        line 6: 4
        line 13: 9
        line 17: 34
        line 18: 42
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      43     0  this   Lcom/app/OtherAction;

  public static void show();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #53                 // String 这是静态方法
         5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 21: 0
        line 22: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

  public void fun();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #56                 // String 这是普通方法
         5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 25: 0
        line 26: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lcom/app/OtherAction;
}

猜你喜欢

转载自blog.csdn.net/oheg2010/article/details/87935100
今日推荐