コードはよりシンプルかつコンパクトになるように、Java8は、Java8ラムダ式がそれを達成する方法で、かなりの程度まで、ラムダ式を増加しましたか?
スレッドを作成する簡単な例で直接見て。
public class TestLambda {
public static void main(String[] args) {
new Thread(() -> System.out.print("thread"));
}
}
実行javac TestLambda.java
コンパイルしたファイルをTestLambda.class
、その後、使用しjavap
たクラスファイルを解析するためのコマンドを。
実行は、javap -p TestLambda
すべてのクラスとメンバーを示します。
// javap -p TestLambda
Compiled from "TestLambda.java"
public class TestLambda {
public TestLambda();
public static void main(java.lang.String[]);
private static void lambda$main$0(); // 编译后生成的
}
コンパイラは、プライベート静的メソッドラムダ式を生成する上記のコードからわかるように。
private static void lambda$main$0();
コマンドを使用してjavap -v -p TestLambda
詳細情報を印刷します。
public class TestLambda
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#24 // java/lang/Object."<init>":()V
#2 = Class #25 // java/lang/Thread
#3 = InvokeDynamic #0:#30 // #0:run:()Ljava/lang/Runnable;
#4 = Methodref #2.#31 // java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
#5 = Fieldref #32.#33 // java/lang/System.out:Ljava/io/PrintStream;
#6 = String #34 // thread
#7 = Methodref #35.#36 // java/io/PrintStream.print:(Ljava/lang/String;)V
#8 = Class #37 // TestLambda
#9 = Class #38 // java/lang/Object
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 LTestLambda;
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 args
#20 = Utf8 [Ljava/lang/String;
#21 = Utf8 lambda$main$0
#22 = Utf8 SourceFile
#23 = Utf8 TestLambda.java
#24 = NameAndType #10:#11 // "<init>":()V
#25 = Utf8 java/lang/Thread
#26 = Utf8 BootstrapMethods
#27 = MethodHandle #6:#39 // 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;
#28 = MethodType #11 // ()V
#29 = MethodHandle #6:#40 // invokestatic TestLambda.lambda$main$0:()V
#30 = NameAndType #41:#42 // run:()Ljava/lang/Runnable;
#31 = NameAndType #10:#43 // "<init>":(Ljava/lang/Runnable;)V
#32 = Class #44 // java/lang/System
#33 = NameAndType #45:#46 // out:Ljava/io/PrintStream;
#34 = Utf8 thread
#35 = Class #47 // java/io/PrintStream
#36 = NameAndType #48:#49 // print:(Ljava/lang/String;)V
#37 = Utf8 TestLambda
#38 = Utf8 java/lang/Object
#39 = Methodref #50.#51 // 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;
#40 = Methodref #8.#52 // TestLambda.lambda$main$0:()V
#41 = Utf8 run
#42 = Utf8 ()Ljava/lang/Runnable;
#43 = Utf8 (Ljava/lang/Runnable;)V
#44 = Utf8 java/lang/System
#45 = Utf8 out
#46 = Utf8 Ljava/io/PrintStream;
#47 = Utf8 java/io/PrintStream
#48 = Utf8 print
#49 = Utf8 (Ljava/lang/String;)V
#50 = Class #53 // java/lang/invoke/LambdaMetafactory
#51 = NameAndType #54:#58 // 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;
#52 = NameAndType #21:#11 // lambda$main$0:()V
#53 = Utf8 java/lang/invoke/LambdaMetafactory
#54 = Utf8 metafactory
#55 = Class #60 // java/lang/invoke/MethodHandles$Lookup
#56 = Utf8 Lookup
#57 = Utf8 InnerClasses
#58 = 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;
#59 = Class #61 // java/lang/invoke/MethodHandles
#60 = Utf8 java/lang/invoke/MethodHandles$Lookup
#61 = Utf8 java/lang/invoke/MethodHandles
{
public TestLambda();
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 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LTestLambda;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: pop
13: return
LineNumberTable:
line 3: 0
line 4: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 args [Ljava/lang/String;
private static void lambda$main$0();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #6 // String thread
5: invokevirtual #7 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
}
SourceFile: "TestLambda.java"
InnerClasses:
public static final #56= #55 of #59; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #27 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:
#28 ()V
#29 invokestatic TestLambda.lambda$main$0:()V
#28 ()V
上に示した:main()のコードのバイトコードのスレッドラインを作成する方法がデコンパイルされています
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: pop
13: return
記載の4: invokedynamic #3
三行目定数プールを見つけ
#3 = InvokeDynamic #0:#30 // #0:run:()Ljava/lang/Runnable;
その中でも、#0
を指すBootstrapMethods:
静的なファクトリメソッドLambdaMetafactory.metafactory
BootstrapMethods:
0: #27 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:
#28 ()V
#29 invokestatic TestLambda.lambda$main$0:()V
#28 ()V
LambdaMetafactory.metafactory
ラムダ式を生成することができますASMは、ソースとして、metafactory方法を内部クラスを使用します
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();
}
TestLambda実行するプロキシクラスを生成したパラメータで、この内部クラスを参照するには、それがありますjava -Djdk.internal.lambda.dumpProxyClasses TestLambda
。実行の終了後に、クラスファイルを生成するために、同じディレクトリにありますTestLambda$$Lambda$1.class
。実行javap -v -p TestLambda$$Lambda$1
クラスデコンパイル。
final class TestLambda$$Lambda$1 implements java.lang.Runnable
minor version: 0
major version: 52
flags: ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
Constant pool:
#1 = Utf8 TestLambda$$Lambda$1
#2 = Class #1 // TestLambda$$Lambda$1
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 java/lang/Runnable
#6 = Class #5 // java/lang/Runnable
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = NameAndType #7:#8 // "<init>":()V
#10 = Methodref #4.#9 // java/lang/Object."<init>":()V
#11 = Utf8 run
#12 = Utf8 Ljava/lang/invoke/LambdaForm$Hidden;
#13 = Utf8 TestLambda
#14 = Class #13 // TestLambda
#15 = Utf8 lambda$main$0
#16 = NameAndType #15:#8 // lambda$main$0:()V
#17 = Methodref #14.#16 // TestLambda.lambda$main$0:()V
#18 = Utf8 Code
#19 = Utf8 RuntimeVisibleAnnotations
{
private TestLambda$$Lambda$1();
descriptor: ()V
flags: ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: return
public void run();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #17 // Method TestLambda.lambda$main$0:()V
3: return
RuntimeVisibleAnnotations:
0: #12()
}
以上から分かるように、内部クラスはTestLambda$$Lambda$1
java.lang.Runnableの実装run()
スレッドが開始した後、それが実行をトリガする実行する方法である方法TestLambda.lambda$main$0:()
、そのコンパイルされてTestLambda
生成されたプライベート静的メソッドを。
概要
スレッドを作成したラムダ式は、このクラスの中に実行コンパイル済みのクラスファイルでプライベート静的メソッドを追加します、技術オペレーションASMバイトコードが動的に内部クラスを生成し使用しますが、この内部クラスは、Runnableインタフェースを実装し、実際の実行のスレッドは、スレッドのrunメソッドは、マルチスレッドコードを実行するために、コンパイラによって生成されたプライベート静的メソッド呼び出しの内側に実際にあります。