☕️【Java 技術之旅】帶你看透Lambda表達式的底層

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"每日一句","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"只要下定決心,過去的失敗,正好是未來行動的借鑑;只要不屈不撓,一時的障礙,正好是推動成功的力量。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前提回顧","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" 之前寫完了一篇【Java 技術之旅】帶你看透 Lambda 表達式的本質】 ","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/f859764824f443776bc95fd1e","title":"","type":null},"content":[{"type":"text","text":"https://xie.infoq.cn/article/f859764824f443776bc95fd1e","attrs":{}}]},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":",","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" 相比較本篇而言是姊妹篇,本篇是基於上一篇的與案例分析,更加深度的分析了一下原理,本篇是主要針對於Lambda表達式的實現原理進行更低層分析,讓讀者可以更加底層面認識一下Lambda的原理。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"筆者建議","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" 希望先看完【","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/f859764824f443776bc95fd1e","title":"","type":null},"content":[{"type":"text","text":"https://xie.infoq.cn/article/f859764824f443776bc95fd1e","attrs":{}}]},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"】再看本篇,會更加符合循序漸進。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Lambda的原理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"Java 8支持動態語言,看到很酷的Lambda表達式,對一直以靜態類型語言自居的Java,讓人看到了Java虛擬機可以支持動態語言的目標。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Lambda的案例","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import java.util.function.Consumer;\npublic class Lambda {\n public static void main(String[] args) {\n Consumer c = s -> System.out.println(s);\n c.accept(\"hello lambda!\");\n }\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Lambda表達式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"剛看到這個表達式,感覺java的處理方式是屬於內部匿名類的方式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class Lambda {\n static {\n System.setProperty(\"jdk.internal.lambda.dumpProxyClasses\", \".\");\n }\n public static void main(String[] args) {\n Consumer c = new Consumer(){\n @Override\n public void accept(String s) {\n System.out.println(s);\n }\n };\n c.accept(\"hello lambda\");\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編譯的結果應該是Lambda.class , Lambda$1.class 猜測在支持動態語言java換湯不換藥,在最後編譯的時候生成我們常見的方式。但是結果不是這樣的,只是產生了一個Lambda.class","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"反編譯吧,來看看真相是什麼?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"javap -v -p Lambda.class \n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"-p 參數會顯示所有的方法,而不帶默認是不會反編譯private的方法的。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"public Lambda();\n descriptor: ()V\n flags: ACC_PUBLIC\n Code:\n stack=1, locals=1, args_size=1\n 0: aload_0\n 1: invokespecial #21 // Method java/lang/Object.\"\":()V\n 4: return\n LineNumberTable:\n line 3: 0\n LocalVariableTable:\n Start Length Slot Name Signature\n 0 5 0 this LLambda;\n public static void main(java.lang.String[]);\n descriptor: ([Ljava/lang/String;)V\n flags: ACC_PUBLIC, ACC_STATIC\n Code:\n stack=2, locals=2, args_size=1\n 0: invokedynamic #30, 0 // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;\n 5: astore_1\n 6: aload_1\n 7: ldc #31 // String hello lambda\n 9: invokeinterface #33, 2 // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V\n 14: return\n LineNumberTable:\n line 8: 0\n line 9: 6\n line 10: 14\n LocalVariableTable:\n Start Length Slot Name Signature\n 0 15 0 args [Ljava/lang/String;\n 6 9 1 c Ljava/util/function/Consumer;\n LocalVariableTypeTable:\n Start Length Slot Name Signature\n 6 9 1 c Ljava/util/function/Consumer;\n \n private static void lambda$0(java.lang.String);\n descriptor: (Ljava/lang/String;)V\n flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC\n Code:\n stack=2, locals=1, args_size=1\n 0: getstatic #46 // Field java/lang/System.out:Ljava/io/PrintStream;\n 3: aload_0\n 4: invokevirtual #50 // Method java/io/PrintStream.println:(Ljava/lang/String;)V\n 7: return\n LineNumberTable:\n line 8: 0\n LocalVariableTable:\n Start Length Slot Name Signature\n 0 8 0 s Ljava/lang/String;\n }\nSourceFile: \"Lambda.java\"\nBootstrapMethods:\n 0: #66 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;\n Method arguments:\n #67 (Ljava/lang/Object;)V\n #70 invokestatic Lambda.lambda$0:(Ljava/lang/String;)V\n #71 (Ljava/lang/String;)V\nInnerClasses:\n public static final #77= #73 of #75; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"重點關注方法","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Invokedynamic","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Java的調用函數的四大指令(invokevirtual、invokespecial、invokestatic、invokeinterface),通常方法的符號引用在靜態類型語言編譯時就能產生。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"動態類型語言只有在運行期才能確定接收者類型,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"改變四大指令的語意對java的版本有很大的影響,所以在JSR 292 《Supporting Dynamically Typed Languages on the Java Platform》添加了一個新的指令:Invokedynamic。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"// InvokeDynamic #0:accept:()Ljava/util/function/Consumer;\n0: invokedynamic #30,0\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"#30 是代表常量#30也就是後面的註釋InvokeDynamic #0:accept:()Ljava/util/function/Consumer;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"0 是佔位符號,目前無用","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"BootstrapMethods","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"每一個invokedynamic指令的實例叫做一個動態調用點(dynamic call site)","attrs":{}},{"type":"text","text":",動態調用點最開始是未鏈接狀態(unlinked):表示還未指定該調用點要調用的方法), 動態調用點依靠引導方法來鏈接到具體的方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"引導方法是由編譯器生成,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"在運行期當JVM第一次遇到invokedynamic指令時, 會調用引導方法來將invokedynamic指令所指定的名字(方法名,方法簽名)和具體的執行代碼(目標方法)鏈接起來, 引導方法的返回值永久的決定了調用點的行爲","attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"CallSite","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"引導方法的返回值類型是java.lang.invoke.CallSite,一個invokedynamic指令關聯一個CallSite,將所有的調用委託到CallSite當前的target(MethodHandle)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"InvokeDynamic #0 就是BootstrapMethods表示#0的位置","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" 0: #66 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;\n Method arguments:\n #67 (Ljava/lang/Object;)V\n #70 invokestatic Lambda.lambda$0:(Ljava/lang/String;)V\n #71 (Ljava/lang/String;)V\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們看到調用了LambdaMetaFactory.metafactory的方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"參數:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"LambdaMetafactory.metafactory(Lookup, String, MethodType, MethodType, MethodHandle, MethodType)","attrs":{}},{"type":"text","text":" 有六個參數, 按順序描述如下","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"MethodHandles.Lookup caller","attrs":{}},{"type":"text","text":" : 代表查找上下文與調用者的訪問權限, 使用invokedynamic指令時, JVM會自動自動填充這個參數。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"String invokedName : 要實現的方法的名字, 使用invokedynamic時, JVM自動幫我們填充(填充內容來自常量池InvokeDynamic.NameAndType.Name), 在這裏JVM爲我們填充爲 \"apply\", 即Consumer.accept方法名","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MethodType invokedType : ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"調用點期望的方法參數的類型和返回值的類型(方法signature)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"使用invokedynamic指令時, JVM會自動自動填充這個參數(填充內容來自常量池InvokeDynamic.NameAndType.Type), 在這裏參數爲String, 返回值類型爲Consumer, 表示這個調用點的目標方法的參數爲String, 然後invokedynamic執行完後會返回一個即Consumer實例","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MethodType samMethodType :  ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"函數對象將要實現的接口方法類型,這裏運行時, 值爲 (Object)Object 即 Consumer.accept方法的類型(泛型信息被擦除)","attrs":{}},{"type":"text","text":"。#67 (Ljava/lang/Object;)V","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MethodHandle implMethod : ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"一個直接方法句柄(DirectMethodHandle), 描述在調用時將被執行的具體實現方法 (包含適當的參數適配, 返回類型適配, 和在調用參數前附加上捕獲的參數)","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏爲 #70 invokestatic Lambda.lambda$0:(Ljava/lang/String;)V 方法的方法句柄.","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MethodType instantiatedMethodType : 函數接口方法替換泛型爲具體類型後的方法類型, 通常和 samMethodType 一樣, 不同的情況爲泛型:","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如函數接口方法定義爲 ","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"void accept(T t)","attrs":{}},{"type":"text","text":" T爲泛型標識, 這個時候方法類型爲(Object)Void。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"在編譯時T已確定, 即T由String替換, 這時samMethodType就是 (Object)Void","attrs":{}},{"type":"text","text":",","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"instantiatedMethodType爲(String)Void","attrs":{}},{"type":"text","text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第4,5,6 三個參數來自class文件中的。如上面引導方法字節碼中Method arguments後面的三個參數就是將應用於4, 5, 6的參數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" Method arguments:\n #67 (Ljava/lang/Object;)V\n #70 invokestatic Lambda.lambda$0:(Ljava/lang/String;)V\n #71 (Ljava/lang/String;)V\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"public static CallSite metafactory(MethodHandles.Lookup caller,\n String invokedName,\n MethodType invokedType,\n MethodType samMethodType,\n MethodHandle implMethod,\n MethodType instantiatedMethodType)\n throws LambdaConversionException {\n AbstractValidatingLambdaMetafactory mf;\n mf = new InnerClassLambdaMetafactory(caller, invokedType,\n invokedName, samMethodType,\n implMethod, instantiatedMethodType,\n false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);\n mf.validateMetafactoryArgs();\n return mf.buildCallSite();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在buildCallSite的函數中","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"CallSite buildCallSite() throws LambdaConversionException {\n final Class> innerClass = spinInnerClass();\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數spinInnerClass 構建了這個內部類,也就是生成了一個Lambda$","attrs":{}},{"type":"katexinline","attrs":{"mathString":"Lambda"}},{"type":"text","text":"1/716157500 這樣的內部類,這個類是在運行的時候構建的,並不會保存在磁盤中,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"如果想看到這個構建的類,可以通過設置環境參數","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"System.setProperty(\"jdk.internal.lambda.dumpProxyClasses\", \".\");\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會在你指定的路徑 ,當前運行路徑上生成這個內部類","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"靜態類","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java在編譯表達式的時候會生成lambda$0靜態私有類方法,在這個方法裏實現了表達式中的方法塊 system.out.println(s);","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"private static void lambda$0(java.lang.String);\n descriptor: (Ljava/lang/String;)V\n flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC\n Code:\n stack=2, locals=1, args_size=1\n 0: getstatic #46 // Field java/lang/System.out:Ljava/io/PrintStream;\n 3: aload_0\n 4: invokevirtual #50 // Method java/io/PrintStream.println:(Ljava/lang/String;)V\n 7: return\n LineNumberTable:\n line 8: 0\n LocalVariableTable:\n Start Length Slot Name Signature\n 0 8 0 s Ljava/lang/String;\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然了在上一步通過設置的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"jdk.internal.lambda.dumpProxyClasses","attrs":{}},{"type":"text","text":"裏生成的","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"Lambda$$Lambda$1.class\n public void accept(java.lang.Object);\n descriptor: (Ljava/lang/Object;)V\n flags: ACC_PUBLIC\n Code:\n stack=1, locals=2, args_size=2\n 0: aload_1\n 1: checkcast #15 // class java/lang/String\n 4: invokestatic #21 // Method Lambda.lambda$0:(Ljava/lang/String;)V\n 7: return\n RuntimeVisibleAnnotations:\n 0: #13()\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"調用了Lambda.lambda$0靜態函數,也就是表達式中的函數塊","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣就完成的實現了Lambda表達式,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"使用invokedynamic指令,運行時調用LambdaMetafactory.metafactory動態的生成內部類,實現了接口","attrs":{}},{"type":"text","text":",","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"內部類裏的調用方法塊並不是動態生成的,只是在原class裏已經編譯生成了一個靜態的方法,內部類只需要調用該靜態方法","attrs":{}}]}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章