這次我們來探究一下其它情況厨相。
package com.github.wanggancheng;
import java.util.function.Consumer;
public class InvokeDynamicDemo {
public static void output(String s){
System.out.println(s);
}
public static void main(String[] args) {
Consumer<String> consumer=InvokeDynamicDemo::output;
consumer.accept("Lambda demo");
}
}
從上面的代碼可以看出鸠项,與先前的主要差異為:用類靜態(tài)方法來替代java Lambda骚灸。我們反編譯class文件的方法信息如下:
public class com.github.wanggancheng.InvokeDynamicDemo {
public com.github.wanggancheng.InvokeDynamicDemo();
public static void output(java.lang.String);
public static void main(java.lang.String[]);
}
從上面的信息來看期虾,并沒有自動(dòng)添加什么方法公你。我們來看看main方法的字節(jié)碼信息踊淳。
public static void main(java.lang.String[]);
Code:
0: invokedynamic #4, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;
5: astore_1
6: aload_1
7: ldc #5 // String Lambda demo
9: invokeinterface #6, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
14: return
從上面可以看出第一條指令還是invokedynamic,有先前的例子沒有什么差別。我們來看更具體的字節(jié)碼信息陕靠。
BootstrapMethods:
0: #36 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:
#37 (Ljava/lang/Object;)V
#38 invokestatic com/github/wanggancheng/InvokeDynamicDemo.output:(Ljava/lang/String;)V
#39 (Ljava/lang/String;)V
從第1個(gè)bootstrapmethod來看迂尝,與第1篇文章中的示例的bootstrapmethod的差異是第2個(gè)參數(shù)。先前的實(shí)例中第2個(gè)參數(shù)是調(diào)用編譯器自動(dòng)生成的一個(gè)靜態(tài)方法ambda$main$0剪芥。
我們來看看一個(gè)稍復(fù)雜的例子垄开。
package com.github.wanggancheng;
import java.util.function.Consumer;
public class InvokeDynamicInstanceMethodDemo {
public void output(String s){
System.out.println(s);
}
public static void main(String[] args) {
InvokeDynamicInstanceMethodDemo instance = new InvokeDynamicInstanceMethodDemo();
Consumer<String> consumer=instance::output;
consumer.accept("Lambda demo");
}
}
反編譯此類的class文件,可以發(fā)現(xiàn)也沒有添加新方法税肪。還是重點(diǎn)來看看bootstrap_method方法信息溉躲。
BootstrapMethods:
0: #41 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:
#42 (Ljava/lang/Object;)V
#43 invokevirtual com/github/wanggancheng/InvokeDynamicInstanceMethodDemo.output:(Ljava/lang/String;)V
#44 (Ljava/lang/String;)V
重點(diǎn)差別為#43,表明調(diào)用類型為invokevirtual而非invokestatic益兄。
invokedynamice_info的信息如下:
#7 = InvokeDynamic #0:#45 // #0:accept:(Lcom/github/wanggancheng/InvokeDynamicInstanceMethodDemo;)Ljava/util/function/Consumer;
從上面的信息可以看出锻梳,與先前的示例的主要差別為invokedType中包含實(shí)例方法引用的類實(shí)例作為參數(shù)。
我們?cè)谶\(yùn)行時(shí)把自動(dòng)生成的類dump出來净捅,反編譯信息如下疑枯。
package com.github.wanggancheng;
import java.lang.invoke.LambdaForm.Hidden;
import java.util.function.Consumer;
// $FF: synthetic class
final class InvokeDynamicInstanceMethodDemo$$Lambda$1 implements Consumer {
private final InvokeDynamicInstanceMethodDemo arg$1;
private InvokeDynamicInstanceMethodDemo$$Lambda$1(InvokeDynamicInstanceMethodDemo var1) {
this.arg$1 = var1;
}
private static Consumer get$Lambda(InvokeDynamicInstanceMethodDemo var0) {
return new InvokeDynamicInstanceMethodDemo$$Lambda$1(var0);
}
@Hidden
public void accept(Object var1) {
this.arg$1.output((String)var1);
}
}
這個(gè)自動(dòng)合成的類之構(gòu)造方法有一個(gè)InvokeDynamicInstanceMethodDemo。這個(gè)參數(shù)就是Consumer引用的實(shí)例方法對(duì)應(yīng)的類實(shí)例蛔六。
跟蹤到InnerClassLambdaMetaFactory的buildCallSite方法荆永。
CallSite最終指向的Method為NAME_FACTORY。這個(gè)常量固定為"get$Lambda"国章。