javap反编译字节码详解<转载>

javap反编译字节码详解

package com.zjj;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
/**
 * create by zhaojiang02 2019-06-01
 */
public final class ClassFileTest {
    private int privateint = 1;
    private static int privatestaticint = 2;
    private static final int privatestaticfinalint = 2;
 
    public int sayHello(String s) throws IOException {
        System.out.println("hello " + s);
        List<Integer> interfaceRef = new ArrayList();
        ArrayList<Integer> classRef = new ArrayList();
 
        interfaceRef.add(1);
        classRef.add(1);
 
        interfaceRef.stream().forEach(System.out::println);
        classRef.stream().forEach(System.out::println);
 
        invokeStatic();
 
        invokeprivate();
 
        super.hashCode();
 
        try {
            System.out.println("try");
        } catch (RuntimeException e) {
            System.out.println("runtimeexception");
        } finally {
            System.out.println("finally");
        }
 
        return 100;
    }
 
    private static void invokeStatic() {
 
    }
 
    private void invokeprivate() {
 
    }
 
}

javap -v -p ClassFileTest.class 反编译

编译后的字节码:

Classfile /Users/george/working/zjjdemo/javatest/target/classes/com/zjj/ClassFileTest.class #class文件的位置

  Last modified 2019-6-2; size 2767 bytes  # class文件的基本信息,最后修改时间,所占大小字节数  

  MD5 checksum 8ed29bfec33883dbfd84fde18936240f # class文件MD5的hash值  

  Compiled from "ClassFileTest.java"  # 源文件类

public final class com.zjj.ClassFileTest

  minor version: 0  # 最小版本

  major version: 52   #最大版本 每个jvm都有能识别的class文件的最小版本和最大版本,超过这个范围,jvm不能进行类的加载

  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER  # 类标识符。本例上,凡是可以在类上的标记都会在这里展示,如static,final等。TestFileTest这个类是publicConstant pool:

# #1=Methodref  等号签名是常量池的编号,从1开始编号,每个常量项占一个编号。等号后面的是该常量项的类型(jvm定义的14中类型)。

#  第二列。如果常量项是一个引用,指向其他的常量项,那地三列就是该向量项指向那个常量项的编号。

#第3列就是常量项的符号引用。全类名/字段名/方法名,以及字段或者方法的描述符。

# 比如第一行:第一个常量项是CONSTANT_Methodref_info类型的,它表示一个方法的常量引用,它的就结构中有两个index:

#第一个是指向该方法的类描述符的常量项(CONSTANT_Class_info)。第二个index是该方法名称及类型的描述符(CONSTANT_NameAndType)

#依次往下找,找到一个完整的方法相关的常量(如下用特殊颜色标注).

#第3列就是符号应用:java.lang.Object.<init>的构造方法,()V方法返回值是void,没有形参表。

 

    #1 = Methodref          #29.#70       // java/lang/Object."<init>":()V

    #2 = Fieldref           #28.#71       // com/zjj/ClassFileTest.privateint:I

    #3 = Fieldref           #72.#73       // java/lang/System.out:Ljava/io/PrintStream;

    #4 = Class              #74           // java/lang/StringBuilder

    #5 = Methodref          #4.#70        // java/lang/StringBuilder."<init>":()V

    #6 = String             #75           // hello  # 字符串的字面常量,值为“hello”(//后的是备注,实际存放这个字面常量的是一个utf8结构,在75行出)

    #7 = Methodref          #4.#76        // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

    #8 = Methodref          #4.#77        // java/lang/StringBuilder.toString:()Ljava/lang/String;

    #9 = Methodref          #78.#79       // java/io/PrintStream.println:(Ljava/lang/String;)V

   #10 = Class              #80           // java/util/ArrayList

   #11 = Methodref          #10.#70       // java/util/ArrayList."<init>":()V

   #12 = Methodref          #81.#82       // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

   #13 = InterfaceMethodref #83.#84       // java/util/List.add:(Ljava/lang/Object;)Z

   #14 = Methodref          #10.#84       // java/util/ArrayList.add:(Ljava/lang/Object;)Z

   #15 = InterfaceMethodref #83.#85       // java/util/List.stream:()Ljava/util/stream/Stream;

   #16 = Methodref          #29.#86       // java/lang/Object.getClass:()Ljava/lang/Class;

   #17 = InvokeDynamic      #0:#92        // #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;

   #18 = InterfaceMethodref #93.#94       // java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V

   #19 = Methodref          #10.#85       // java/util/ArrayList.stream:()Ljava/util/stream/Stream;

   #20 = Methodref          #28.#95       // com/zjj/ClassFileTest.invokeStatic:()V

   #21 = Methodref          #28.#96       // com/zjj/ClassFileTest.invokeprivate:()V

   #22 = Methodref          #29.#97       // java/lang/Object.hashCode:()I

   #23 = String             #98           // try

   #24 = String             #99           // finally

   #25 = Class              #100          // java/lang/RuntimeException

   #26 = String             #101          // runtimeexception

   #27 = Fieldref           #28.#102      // com/zjj/ClassFileTest.privatestaticint:I

   #28 = Class              #103          // com/zjj/ClassFileTest

   #29 = Class              #104          // java/lang/Object

   #30 = Utf8               privateint

# 类型描述符。I:int;J:long;Z:boolean;[:数组,如[J表示long数组;L:对象类型,Ljava/lang/Object表示Object引用类型

#其他的都是类型的首字母大写。注意boolean,long,引用类型的特殊

   #31 = Utf8               I    

   #32 = Utf8               privatestaticint

   #33 = Utf8               privatestaticfinalint

   #34 = Utf8               ConstantValue

   #35 = Integer            2

   #36 = Utf8               <init>

   #37 = Utf8               ()V

   #38 = Utf8               Code

   #39 = Utf8               LineNumberTable

   #40 = Utf8               LocalVariableTable

   #41 = Utf8               this

   #42 = Utf8               Lcom/zjj/ClassFileTest;

   #43 = Utf8               sayHello

#方法描述符,括号里是形参的类型描述符,括号后是返回这类型描述符

#如下的方法是:入参是一个String类型的引用,返回值是int类型的方法描述符

   #44 = Utf8               (Ljava/lang/String;)I  

   #45 = Utf8               e # 字符串常量。实际的String字面常量,方法名,类名,字段名都是用utf8结构

   #46 = Utf8               Ljava/lang/RuntimeException;

   #47 = Utf8               s

   #48 = Utf8               Ljava/lang/String;

   #49 = Utf8               interfaceRef

   #50 = Utf8               Ljava/util/List;

   #51 = Utf8               classRef

   #52 = Utf8               Ljava/util/ArrayList;

   #53 = Utf8               LocalVariableTypeTable

   #54 = Utf8               Ljava/util/List<Ljava/lang/Integer;>;

   #55 = Utf8               Ljava/util/ArrayList<Ljava/lang/Integer;>;

   #56 = Utf8               StackMapTable

   #57 = Class              #103          // com/zjj/ClassFileTest

   #58 = Class              #105          // java/lang/String

   #59 = Class              #106          // java/util/List

   #60 = Class              #80           // java/util/ArrayList

   #61 = Class              #100          // java/lang/RuntimeException

   #62 = Class              #107          // java/lang/Throwable

   #63 = Utf8               Exceptions

   #64 = Class              #108          // java/io/IOException

   #65 = Utf8               invokeStatic

   #66 = Utf8               invokeprivate

   #67 = Utf8               <clinit>

   #68 = Utf8               SourceFile

   #69 = Utf8               ClassFileTest.java

   #70 = NameAndType        #36:#37       // "<init>":()V

   #71 = NameAndType        #30:#31       // privateint:I

   #72 = Class              #109          // java/lang/System

   #73 = NameAndType        #110:#111     // out:Ljava/io/PrintStream;

   #74 = Utf8               java/lang/StringBuilder

   #75 = Utf8               hello

   #76 = NameAndType        #112:#113     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

   #77 = NameAndType        #114:#115     // toString:()Ljava/lang/String;

   #78 = Class              #116          // java/io/PrintStream

   #79 = NameAndType        #117:#118     // println:(Ljava/lang/String;)V

   #80 = Utf8               java/util/ArrayList

   #81 = Class              #119          // java/lang/Integer

   #82 = NameAndType        #120:#121     // valueOf:(I)Ljava/lang/Integer;

   #83 = Class              #106          // java/util/List

   #84 = NameAndType        #122:#123     // add:(Ljava/lang/Object;)Z

   #85 = NameAndType        #124:#125     // stream:()Ljava/util/stream/Stream;

   #86 = NameAndType        #126:#127     // getClass:()Ljava/lang/Class;

   #87 = Utf8               BootstrapMethods

   #88 = MethodHandle       #6:#128       // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

   #89 = MethodType         #129          //  (Ljava/lang/Object;)V

   #90 = MethodHandle       #5:#130       // invokevirtual java/io/PrintStream.println:(Ljava/lang/Object;)V

   #91 = MethodType         #131          //  (Ljava/lang/Integer;)V

   #92 = NameAndType        #132:#133     // accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;

   #93 = Class              #134          // java/util/stream/Stream

   #94 = NameAndType        #135:#136     // forEach:(Ljava/util/function/Consumer;)V

   #95 = NameAndType        #65:#37       // invokeStatic:()V

   #96 = NameAndType        #66:#37       // invokeprivate:()V

   #97 = NameAndType        #137:#138     // hashCode:()I

   #98 = Utf8               try

   #99 = Utf8               finally

  #100 = Utf8               java/lang/RuntimeException

  #101 = Utf8               runtimeexception

  #102 = NameAndType        #32:#31       // privatestaticint:I

  #103 = Utf8               com/zjj/ClassFileTest

  #104 = Utf8               java/lang/Object

  #105 = Utf8               java/lang/String

  #106 = Utf8               java/util/List

  #107 = Utf8               java/lang/Throwable

  #108 = Utf8               java/io/IOException

  #109 = Utf8               java/lang/System

  #110 = Utf8               out

  #111 = Utf8               Ljava/io/PrintStream;

  #112 = Utf8               append

  #113 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;

  #114 = Utf8               toString

  #115 = Utf8               ()Ljava/lang/String;

  #116 = Utf8               java/io/PrintStream

  #117 = Utf8               println

  #118 = Utf8               (Ljava/lang/String;)V

  #119 = Utf8               java/lang/Integer

  #120 = Utf8               valueOf

  #121 = Utf8               (I)Ljava/lang/Integer;

  #122 = Utf8               add

  #123 = Utf8               (Ljava/lang/Object;)Z

  #124 = Utf8               stream

  #125 = Utf8               ()Ljava/util/stream/Stream;

  #126 = Utf8               getClass

  #127 = Utf8               ()Ljava/lang/Class;

  #128 = Methodref          #139.#140     // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #129 = Utf8               (Ljava/lang/Object;)V

  #130 = Methodref          #78.#141      // java/io/PrintStream.println:(Ljava/lang/Object;)V

  #131 = Utf8               (Ljava/lang/Integer;)V

  #132 = Utf8               accept

  #133 = Utf8               (Ljava/io/PrintStream;)Ljava/util/function/Consumer;

  #134 = Utf8               java/util/stream/Stream

  #135 = Utf8               forEach

  #136 = Utf8               (Ljava/util/function/Consumer;)V

  #137 = Utf8               hashCode

  #138 = Utf8               ()I

  #139 = Class              #142          // java/lang/invoke/LambdaMetafactory

  #140 = NameAndType        #143:#147     // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #141 = NameAndType        #117:#129     // println:(Ljava/lang/Object;)V

  #142 = Utf8               java/lang/invoke/LambdaMetafactory

  #143 = Utf8               metafactory

  #144 = Class              #149          // java/lang/invoke/MethodHandles$Lookup

  #145 = Utf8               Lookup

  #146 = Utf8               InnerClasses

  #147 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #148 = Class              #150          // java/lang/invoke/MethodHandles

  #149 = Utf8               java/lang/invoke/MethodHandles$Lookup

  #150 = Utf8               java/lang/invoke/MethodHandles

{undefined

#如下是字段表

  private int privateint;

    descriptor: I  #字段描述符,I表示是一个int型的

    flags: ACC_PRIVATE #字段的标志,如可见性修饰符,static,final等

 

  private static int privatestaticint;

    descriptor: I

    flags: ACC_PRIVATE, ACC_STATIC

 

  private static final int privatestaticfinalint;

    descriptor: I

    flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL

    # javac限制static final字段有ConstantValue属性,该属性记录了字段的值。 这并不是java规范限制的,java规范描述是static字段可以有ConstantValue属性。

    ConstantValue: int 2 

 

#如下是方法表

  public com.zjj.ClassFileTest();#方法定义,和类同名,所以是构造方法

    descriptor: ()V  #方法描述符。

    flags: ACC_PUBLIC # 方法的标志位

   #如下是方法的Code属性,是方法最重要的部分,方法体编译后产生的字节码都放在Code属性中 

   Code:

# stack=2:运行该方法所需要的最大操作数栈深度是2.

#locals=1:运行该方法所需要的最大局部方法表的最大slot数是1

#args_size:该方法的形参个数。如果是实例方法,第一个形参是this引用。

      stack=2, locals=1, args_size=1

         0: aload_0

         1: invokespecial #1                  // Method java/lang/Object."<init>":()V

         4: aload_0

         5: iconst_1

         6: putfield      #2                  // Field privateint:I

         9: return

      LineNumberTable:

        line 10: 0

        line 11: 4

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0      10     0  this   Lcom/zjj/ClassFileTest;

 

  public int sayHello(java.lang.String) throws java.io.IOException;#实例方法

    descriptor: (Ljava/lang/String;)I

    flags: ACC_PUBLIC

    Code:

      stack=3, locals=6, args_size=2

# 第一列是字节码偏移量

#第二列是字节码助记符

#第三列是字节码操作数,#3表示引用了常量池编号为3的项。

# 第4列可以理解是一个注释。注解giant指令完成的事情

         0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream; #获取类的static变量的值,并压入栈顶。这里其实是获得PrintStream的类名

        #new 是创建对象,如果对应的类没有加载,将触发类加载过程,new是为对象分配内存等初始化属性的前面过程。注意invokespecial调用构造方法已经是在初始化对象了。 

3: new           #4                  // class java/lang/StringBuilder # 字符串+,编译后new了一个StringBuilder来完成字符串的拼接的

         6: dup             #dup:将栈顶元素复制一份压入栈顶

         7: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V  #调用构造方法,这里调用的是StringBuilder的构造方法

        #ldc:从运行时常量区提取常量压入操作数栈栈顶。

# #6表示提取的常量是class文件的常量池的第6项常量,查看常量池发现第6项是一个utf8结构,值就是”hello”

# class文件的常量池中的内容,类加载后会放到运行时方法区的常量区。所以这里就是从运行时方法区的常量池将”hello”这个

# 字符串压入到操作数栈栈顶。

10: ldc           #6                  // String hello 

# invokevirtual调用实例方法,#7指向常量池的method_ref,是一个方法引用结构。

        12: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

        15: aload_1 #将局部方法表的第1个slot中的引用类型值压入栈顶

        16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

        19: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

        22: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

        25: new           #10                 // class java/util/ArrayList

        28: dup

        29: invokespecial #11                 // Method java/util/ArrayList."<init>":()V

        32: astore_2 #将操作数栈栈顶引用类型元素出栈,放到局部变量表的第2个slot中

        33: new           #10                 // class java/util/ArrayList

        36: dup

#invokespecial指令调用构造方法,private方法,父类方法(super.方法名)也是通过invokespecial调用

        37: invokespecial #11                 // Method java/util/ArrayList."<init>”:()V

        40: astore_3

        41: aload_2

        42: iconst_1  # 将int型的常量1压入到操作数栈的栈顶

        43: invokestatic  #12                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

#调用接口方法(接口名.方法名),具体执行该指令时,该指令会查找实现该接口的实现类对应的方法

        46: invokeinterface #13,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z

        51: pop # 弹出操作数栈栈顶元素

        52: aload_3

        53: iconst_1

        54: invokestatic  #12                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#invokestatic调用static方法

        57: invokevirtual #14                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z

        60: pop

        61: aload_2

        62: invokeinterface #15,  1           // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;

        67: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

        70: dup

        71: invokevirtual #16                 // Method java/lang/Object.getClass:()Ljava/lang/Class;

        74: pop

#invokedynamic 动态指令,java8中的lambda表达式会编译成invokedynamic指令

        75: invokedynamic #17,  0             // InvokeDynamic #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;

        80: invokeinterface #18,  2           // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V

        85: aload_3

        86: invokevirtual #19                 // Method java/util/ArrayList.stream:()Ljava/util/stream/Stream;

        89: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

        92: dup

        93: invokevirtual #16                 // Method java/lang/Object.getClass:()Ljava/lang/Class;

        96: pop

        97: invokedynamic #17,  0             // InvokeDynamic #0:accept:(Ljava/io/PrintStream;)Ljava/util/function/Consumer;

       102: invokeinterface #18,  2           // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V

       107: invokestatic  #20                 // Method invokeStatic:()V

       110: aload_0

       111: invokespecial #21                 // Method invokeprivate:()V

       114: aload_0

       115: invokespecial #22                 // Method java/lang/Object.hashCode:()I

       118: pop

       119: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

       122: ldc           #23                 // String try

       124: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

       127: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

       130: ldc           #24                 // String finally

       132: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

       135: goto          172  #goto 无条件跳转。跳转到172位置的指令执行

       138: astore        4

       140: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

       143: ldc           #26                 // String runtimeexception

       145: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

       148: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

       151: ldc           #24                 // String finally

       153: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

       156: goto          172

       159: astore        5

       161: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

       164: ldc           #24                 // String finally

       166: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

       169: aload         5 # aload index和aload_<n> 一样的,都是将局部变量表的第index/n个slot引用型变量压入操作数栈栈顶

       171: athrow   #抛出一个异常

       172: bipush        100  #bipush将一个byte型数据入栈。这里就是将100压栈

       174: ireturn  #返回栈顶的int型数据,在xxreturn指令的前一个压栈指令,其实就是为返回作准备的

      

       Exception table:#异常表

#from to target都是Code属性中的字节码偏移量(Code属性第一列)

#表示当在执行从from到to之间的字节码的时候,如果抛出type指定的异常,就无条件挑战到target出的字节指令往下执行

         from    to  target type

           119   127   138   Class java/lang/RuntimeException

           119   127   159   any

           138   148   159   any

           159   161   159   any

      LineNumberTable:

        line 16: 0 # 16是源码的行号。0是该源码行对应的字节码开始偏移量。所以源码的第16行含义成指令是0~24(对应Code属性的第一列的值)

        line 17: 25

        line 18: 33

        line 20: 41

        line 21: 52

        line 23: 61

        line 24: 85

        line 26: 107

        line 28: 110

        line 30: 114

        line 33: 119

        line 37: 127

        line 38: 135

        line 34: 138

        line 35: 140

        line 37: 148

        line 38: 156

        line 37: 159

        line 40: 172

      LocalVariableTable:#栈帧局部变量表中的变量和源码中定义的变量之间的关系

#star和length:说明该变量的生命周期,生命期是从第start个指令开始,往后数lenght个长度的指令。

#slot:只是改变量在局部变量表中slot的编号。

#name:局部变量名称

#signature: 可以认为是变量类型描述符

        Start  Length  Slot  Name   Signature

          140       8     4     e   Ljava/lang/RuntimeException;

            0     175     0  this   Lcom/zjj/ClassFileTest;

            0     175     1     s   Ljava/lang/String;

           33     142     2 interfaceRef   Ljava/util/List;

           41     134     3 classRef   Ljava/util/ArrayList;

      LocalVariableTypeTable:#有泛型的时候会有该属性。由于擦除,方法的描述符不能准确描述泛型类型,所以用这个属性来记录源码中泛型的实际类型

        Start  Length  Slot  Name   Signature

           33     142     2 interfaceRef   Ljava/util/List<Ljava/lang/Integer;>;

           41     134     3 classRef   Ljava/util/ArrayList<Ljava/lang/Integer;>;

      StackMapTable: number_of_entries = 3  #验证阶段用于类型验证优化使用

        frame_type = 255 /* full_frame */

          offset_delta = 138

          locals = [ class com/zjj/ClassFileTest, class java/lang/String, class java/util/List, class java/util/ArrayList ]

          stack = [ class java/lang/RuntimeException ]

        frame_type = 84 /* same_locals_1_stack_item */

          stack = [ class java/lang/Throwable ]

        frame_type = 12 /* same */

    Exceptions:#Exceptions属性,方法有throws申明的时候会有该属性

      throws java.io.IOException

 

  private static void invokeStatic();

    descriptor: ()V

    flags: ACC_PRIVATE, ACC_STATIC

    Code:

      stack=0, locals=0, args_size=0

         0: return

      LineNumberTable:

        line 45: 0

 

  private void invokeprivate();

    descriptor: ()V

    flags: ACC_PRIVATE

    Code:

      stack=0, locals=1, args_size=1

         0: return

      LineNumberTable:

        line 49: 0

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0       1     0  this   Lcom/zjj/ClassFileTest;

 

  static {};#static变量初始化以及static块对应的<cinit>方法

    descriptor: ()V

    flags: ACC_STATIC

    Code:

      stack=1, locals=0, args_size=0

         0: iconst_2

         1: putstatic     #27                 // Field privatestaticint:I

         4: return

      LineNumberTable:

        line 12: 0

}

SourceFile: "ClassFileTest.java" #class文件的SourceFile属性

InnerClasses:

     public static final #145= #144 of #148; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles

BootstrapMethods:#class文件的BootstrapMethods属性

# 每一项都是一个启动方法。

#第1列是编号,从0开始

#第2列是指向常量池的引用,它指向的是一个CONSTANT_DynamicInvoke_info的接口。

#第3列是一个方法调用指令,就是调用引导方法。

 

# 源码:classRef.stream().forEach(System.out::println); classRef=ArrayList<Interger>

#LambdaMetafactory.metafactory(MethodHandle#LookU[,String,MethodType, MethodType, MethodHandle MethodType)CallSite  调用这个方法,返回一个CallSite引用

# 调用该方法的参数(BootStrapMethods属性的bootstrap_mthods属性的bootstrapmethod_arguments中存储了这些参数)

  0: #88 invoke static java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

    Method arguments:

      #89 (Ljava/lang/Object;)V

      #90 invokevirtual java/io/PrintStream.println:(Ljava/lang/Object;)V

      #91 (Ljava/lang/Integer;)V

#############################invokedynamic相关字节码单拿出来看##################################

源码:

public class Main {undefined

    public static void main(String[] args) {undefined

        Runnable r = ()->{undefined

            System.out.println("hello");

        };

    }

}

 

#字节码:只是将和lambda表达式相关的BootStrapMethods属性以及CONSTANT_DynamicInvoke长两项单独列出来了

Constant pool:()

#1 = Methodref          #7.#24         // java/lang/Object."<init>":()V

   #2 = InvokeDynamic      #0:#29         // #0:run:()Ljava/lang/Runnable;

   #3 = Fieldref           #30.#31        // java/lang/System.out:Ljava/io/PrintStream;

   #4 = String             #32            // hello

   #5 = Methodref          #33.#34        // java/io/PrintStream.println:(Ljava/lang/String;)V

   #6 = Class              #35            // com/zjj/Main

   #7 = Class              #36            // java/lang/Object

   #8 = Utf8               <init>

   #9 = Utf8               ()V

  #10 = Utf8               Code

  #11 = Utf8               LineNumberTable

  #12 = Utf8               LocalVariableTable

  #13 = Utf8               this

  #14 = Utf8               Lcom/zjj/Main;

  #15 = Utf8               main

  #16 = Utf8               ([Ljava/lang/String;)V

  #17 = Utf8               args

  #18 = Utf8               [Ljava/lang/String;

  #19 = Utf8               r

  #20 = Utf8               Ljava/lang/Runnable;

  #21 = Utf8               lambda$main$0

  #22 = Utf8               SourceFile

  #23 = Utf8               Main.java

  #24 = NameAndType        #8:#9          // "<init>":()V

  #25 = Utf8               BootstrapMethods

  #26 = MethodHandle       #6:#37         // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #27 = MethodType         #9             //  ()V

  #28 = MethodHandle       #6:#38         // invokestatic com/zjj/Main.lambda$main$0:()V

  #29 = NameAndType        #39:#40        // run:()Ljava/lang/Runnable;

  #30 = Class              #41            // java/lang/System

  #31 = NameAndType        #42:#43        // out:Ljava/io/PrintStream;

  #32 = Utf8               hello

  #33 = Class              #44            // java/io/PrintStream

  #34 = NameAndType        #45:#46        // println:(Ljava/lang/String;)V

  #35 = Utf8               com/zjj/Main

  #36 = Utf8               java/lang/Object

  #37 = Methodref          #47.#48        // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #38 = Methodref          #6.#49         // com/zjj/Main.lambda$main$0:()V

  #39 = Utf8               run

  #40 = Utf8               ()Ljava/lang/Runnable;

  #41 = Utf8               java/lang/System

  #42 = Utf8               out

  #43 = Utf8               Ljava/io/PrintStream;

  #44 = Utf8               java/io/PrintStream

  #45 = Utf8               println

  #46 = Utf8               (Ljava/lang/String;)V

  #47 = Class              #50            // java/lang/invoke/LambdaMetafactory

  #48 = NameAndType        #51:#55        // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #49 = NameAndType        #21:#9         // lambda$main$0:()V

  #50 = Utf8               java/lang/invoke/LambdaMetafactory

  #51 = Utf8               metafactory

  #52 = Class              #57            // java/lang/invoke/MethodHandles$Lookup

  #53 = Utf8               Lookup

  #54 = Utf8               InnerClasses

  #55 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

  #56 = Class              #58            // java/lang/invoke/MethodHandles

  #57 = Utf8               java/lang/invoke/MethodHandles$Lookup

  #58 = Utf8               java/lang/invoke/MethodHandles  

 

 public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

      stack=1, locals=2, args_size=1

         0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;

         5: astore_1

         6: return

      LineNumberTable:

        line 6: 0

        line 9: 6

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0       7     0  args   [Ljava/lang/String;

            6       1     1     r   Ljava/lang/Runnable;

 

  private static void lambda$main$0();#lambda表达式,编译器生成了一个方法,器内容就是lambda表达式中的代码编译后的字节码。

    descriptor: ()V

    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC

    Code:

      stack=2, locals=0, args_size=0

         0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;

         3: ldc           #4                  // String hello

         5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

         8: return

      LineNumberTable:

        line 7: 0

        line 8: 8

 

BootstrapMethods:

  #0 : #26 这一长串翻译过来就是在Main这个类中调用了静态方法LambdaMetafactory.metafactory()方法(这个方法的定义和作用见jdk描述)

  0: #26 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

    Method arguments:

      #27 ()V

      #28 invokestatic com/zjj/Main.lambda$main$0:()V    #调用静态方法Main.lambda$main$0:()V ,这个方法是有lambda表达式编译器自动生成的。

      #27 ()V

————————————————
版权声明:本文为CSDN博主「georgesnoopy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sinat_14913533/article/details/90738019

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值