バイトコードによって達成ディスプレイJava8ラムダ

コードはよりシンプルかつコンパクトになるように、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$1java.lang.Runnableの実装run()スレッドが開始した後、それが実行をトリガする実行する方法である方法TestLambda.lambda$main$0:()、そのコンパイルされてTestLambda生成されたプライベート静的メソッドを。

概要

スレッドを作成したラムダ式は、このクラスの中に実行コンパイル済みのクラスファイルでプライベート静的メソッドを追加します、技術オペレーションASMバイトコードが動的に内部クラスを生成し使用しますが、この内部クラスは、Runnableインタフェースを実装し、実際の実行のスレッドは、スレッドのrunメソッドは、マルチスレッドコードを実行するために、コンパイラによって生成されたプライベート静的メソッド呼び出しの内側に実際にあります。

おすすめ

転載: www.cnblogs.com/bigshark/p/11257395.html