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这个类是public的
Constant 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