2015-10-09 6 views
13

2回目のパススルーでスニペットが真に印刷されるのはなぜですか?新しいインスタンスではないはずですか?Javaラムダの平等またはインスタンシエーションについて

import java.util.function.Supplier; 

public class Foo { 
    public static void main(String[] args) throws Exception { 
     Supplier<Long> old =() -> System.nanoTime(); 

     for (int i = 0; i < 3; i++) { 
      /* false true true 
      Supplier<Long> foo = System::nanoTime;*/ 

      Supplier<Long> foo =() -> System.nanoTime(); 

      /* false false false 
      Supplier<Long> foo = new Supplier<Long>() { 
       @Override 
       public Long get() { 
        return System.nanoTime(); 
       } 
      }; 
      //*/ 

      System.out.printf("%s %s %s%n", foo == old, foo, old); 

      old = foo; 
     } 
    } 
} 

false Foo$$Lambda$2/[email protected] Foo$$Lambda$1/[email protected] 
true Foo$$Lambda$2/[email protected] Foo$$Lambda$2/[email protected] 
true Foo$$Lambda$2/[email protected] Foo$$Lambda$2/[email protected] 
+2

私はそれがコンパイラの最適化だと思います。ループの反復ごとに新しいインスタンスを作成する必要はないため、コンパイラは気にしません。 – megaflop

+3

関連:http://stackoverflow.com/questions/24095875/is-there-a-way-to-compare-lambdas –

+0

なぜ関係のないコメントを追加するために編集しましたか? –

答えて

11

ラムダの実装方法については、このarticleをチェックしてください。

は基本的に、コンパイラは、あなたのクラスの次の静的メソッドへのあなたの2 System.nanoTime()なっ:

static Long lambda$1() { 
    return System.nanoTime(); 
} 

static Long lambda$2() { 
    return System.nanoTime(); 
} 

をそしてLambdaMetaFactoryを使用してSupplier<Long>に各ターゲット型付けに一定の基準を作成しました。率直に言って、私は、Javaコンパイラがラムダ本体が同一であり、1つのインスタンスしか作成しないことに気付かなかったことに失望しています。 Javaコンパイラが十分にスマートだった場合は、すべての行にtrue

+2

コンパイラが 'lambda $ 1()'と 'lambda $ 2()'を1つのメソッドに折りたたむほどスマートであったとしても、そのメソッドを参照する異なるラムダ作成サイトは依然として異なるオブジェクトインスタンス(さらには異なるクラス)を生成します。これは、 'System :: nanoTime'のようなメソッド参照を複数回使用することで簡単に証明できます。これは、合成メソッドが生成されないのと同じターゲットメソッドを指しているからです。それでも、オラクルの現在の実装*を考慮すると、それらは異なるオブジェクト*に変換されます。 – Holger

関連する問題