廢話不說上源碼java
public static void main(String[] args) { Function<String, Integer> s = Integer::parseInt; s.apply("10"); }
::具體看下一節app
javap -v -p StreamTest
結果以下函數
警告: 二進制文件StreamTest包含com.cui.subject.java.function.StreamTest Classfile /E:/WorkSpace/subject/java/target/classes/com/cui/subject/java/function/StreamTest.class Last modified 2020-6-15; size 1311 bytes MD5 checksum 7b5bc92830d2402bc0d88bfe91926d3e Compiled from "StreamTest.java" public class com.cui.subject.java.function.StreamTest minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#24 // java/lang/Object."<init>":()V #2 = InvokeDynamic #0:#30 // #0:apply:()Ljava/util/function/Function; #3 = String #31 // 10 #4 = InterfaceMethodref #32.#33 // java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object; #5 = Class #34 // com/cui/subject/java/function/StreamTest #6 = Class #35 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/cui/subject/java/function/StreamTest; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = Utf8 args #17 = Utf8 [Ljava/lang/String; #18 = Utf8 s #19 = Utf8 Ljava/util/function/Function; #20 = Utf8 LocalVariableTypeTable #21 = Utf8 Ljava/util/function/Function<Ljava/lang/String;Ljava/lang/Integer;>; #22 = Utf8 SourceFile #23 = Utf8 StreamTest.java #24 = NameAndType #7:#8 // "<init>":()V #25 = Utf8 BootstrapMethods #26 = MethodHandle #6:#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; #27 = MethodType #37 // (Ljava/lang/Object;)Ljava/lang/Object; #28 = MethodHandle #6:#38 // invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I #29 = MethodType #39 // (Ljava/lang/String;)Ljava/lang/Integer; #30 = NameAndType #40:#41 // apply:()Ljava/util/function/Function; #31 = Utf8 10 #32 = Class #42 // java/util/function/Function #33 = NameAndType #40:#37 // apply:(Ljava/lang/Object;)Ljava/lang/Object; #34 = Utf8 com/cui/subject/java/function/StreamTest #35 = Utf8 java/lang/Object #36 = Methodref #43.#44 // 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; #37 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; #38 = Methodref #45.#46 // java/lang/Integer.parseInt:(Ljava/lang/String;)I #39 = Utf8 (Ljava/lang/String;)Ljava/lang/Integer; #40 = Utf8 apply #41 = Utf8 ()Ljava/util/function/Function; #42 = Utf8 java/util/function/Function #43 = Class #47 // java/lang/invoke/LambdaMetafactory #44 = NameAndType #48:#52 // 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; #45 = Class #53 // java/lang/Integer #46 = NameAndType #54:#55 // parseInt:(Ljava/lang/String;)I #47 = Utf8 java/lang/invoke/LambdaMetafactory #48 = Utf8 metafactory #49 = Class #57 // java/lang/invoke/MethodHandles$Lookup #50 = Utf8 Lookup #51 = Utf8 InnerClasses #52 = 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; #53 = Utf8 java/lang/Integer #54 = Utf8 parseInt #55 = Utf8 (Ljava/lang/String;)I #56 = Class #58 // java/lang/invoke/MethodHandles #57 = Utf8 java/lang/invoke/MethodHandles$Lookup #58 = Utf8 java/lang/invoke/MethodHandles { public com.cui.subject.java.function.StreamTest(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 11: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/cui/subject/java/function/StreamTest; 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: invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function; 5: astore_1 6: aload_1 7: ldc #3 // String 10 9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object; 14: pop 15: return LineNumberTable: line 13: 0 line 14: 6 line 17: 15 LocalVariableTable: Start Length Slot Name Signature 0 16 0 args [Ljava/lang/String; 6 10 1 s Ljava/util/function/Function; LocalVariableTypeTable: Start Length Slot Name Signature 6 10 1 s Ljava/util/function/Function<Ljava/lang/String;Ljava/lang/Integer;>; } SourceFile: "StreamTest.java" InnerClasses: public static final #50= #49 of #56; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 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 (Ljava/lang/Object;)Ljava/lang/Object; #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I #29 (Ljava/lang/String;)Ljava/lang/Integer;
#2 = InvokeDynamic #0:#30 // #0:apply:()Ljava/util/function/Function;
BootstrapMethods: 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 (Ljava/lang/Object;)Ljava/lang/Object; #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I #29 (Ljava/lang/String;)Ljava/lang/Integer;
每個invokedynamic指令的實例叫作一個動態調用點(dynamic call site), 動態調用點最開始是未連接狀態(unlinked:表示還未指定該調用點要調用的方法), 動態調用點依靠引導方法來連接到具體的方法. 引導方法是由編譯器生成, 在運行期當JVM第一次遇到invokedynamic指令時, 會調用引導方法來將invokedynamic指令所指定的名字(方法名,方法簽名)和具體的執行代碼(目標方法)連接起來, 引導方法的返回值永久的決定了調用點的行爲.引導方法的返回值類型是java.lang.invoke.CallSite, 一個invokedynamic指令關聯一個CallSite, 將全部的調用委託到CallSite當前的target(MethodHandle)ui
public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { AbstractValidatingLambdaMetafactory mf; mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); mf.validateMetafactoryArgs(); //此處會建立一個內部類 return mf.buildCallSite(); }
4 5 6 三個參數this
#27 (Ljava/lang/Object;)Ljava/lang/Object; #28 invokestatic java/lang/Integer.parseInt:(Ljava/lang/String;)I #29 (Ljava/lang/String;)Ljava/lang/Integer;
//此處會建立一個內部類 return mf.buildCallSite();
生成的內部類以下
加上這句話線程
System.setProperty("jdk.internal.lambda.dumpProxyClasses", "E:\\WorkSpace\\subject\\lambda\\");
會在指定目錄生成內部類,以下code
final class StreamTest$$Lambda$1 implements Function { private StreamTest$$Lambda$1() { } @Hidden public Object apply(Object var1) { return Integer.parseInt((String)var1); } }
若是是這樣的代碼對象
new Thread(() -> System.out.println("線程:" + Thread.currentThread().getId())).start();
生成的內部類長這樣接口
final class StreamTest$$Lambda$1 implements Runnable { private StreamTest$$Lambda$1() { } @Hidden public void run() { StreamTest.lambda$main$0(); } }
這樣呢ip
Consumer<String> consumer = Integer::parseInt;
就長這樣
final class StreamTest$$Lambda$1 implements Consumer { private StreamTest$$Lambda$1() { } @Hidden public void accept(Object var1) { Integer.parseInt((String)var1); } }
這樣呢
public static void main(String[] args) { Func add = (x, y) -> x + y; System.out.println(add.exec(1, 2)); } @FunctionalInterface interface Func { int exec(int x, int y); }
就長這樣
final class StreamTest$$Lambda$1 implements Func { private StreamTest$$Lambda$1() { } @Hidden public int exec(int var1, int var2) { return StreamTest.lambda$main$0(var1, var2); } }
表明執行哪一個方法
#30 = NameAndType #40:#41 // apply:()Ljava/util/function/Function;
Lambda表達式,使用invokedynamic指令,運行時調用LambdaMetafactory.metafactory動態的生成內部類,實現了接口
內部類裏的調用方法塊並非動態生成的,只是在原class裏已經編譯生成了一個靜態的方法,內部類只須要調用該靜態方法