2015-11-20 15 views
6


匿名クラス定義から格納するオブジェクトを取得するクラスを作成します。私はそれを達成するためにジェネリック型のクラスを使いました。次に、このオブジェクトを操作するパラメータとして取得する機能的インタフェースを使用して、いくつかの操作を定義します。
コードは言葉以上のことを言います。だから、これを見て:汎用パラメータとしての匿名クラス

public class Test<T> { 
    @FunctionalInterface 
    public interface operation<T> { 
     void execute(T object); 
    } 
    private T obj; 
    public Test(T _obj){ 
     obj = _obj; 
    } 
    public void runOperation(operation<T> op){ 
     op.execute(obj); 
    } 

    public static void main(String[] args){ 
     Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }); 
     t.runOperation((o) -> { 
      System.out.println(o.text); // text cannot be resolved 
     }); 
    } 
} 

私の問題は、機能インタフェースの実装でo.textは解決できないということです。これは何らかの種類の消去の結果ですか?
興味深いのは、コンストラクタで機能インタフェースを実装するときに、このコードを動作させることができるということです。
は、このコードを見てください:

public class Test<T> { 
    @FunctionalInterface 
    public interface operation<T> { 
     void execute(T object); 
    } 
    private T obj; 
    private operation<T> op; 

    public Test(T _obj, operation<T> _op){ 
     obj = _obj; 
     op = _op; 
    } 
    public void runOperation(){ 
     op.execute(obj); 
    } 
    public static void main(String[] args){ 
     Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }, (o) -> { 
      System.out.println(o.text); 
     }); 
     t.runOperation(); 
    } 
} 

これは完璧に動作し、「何か」を出力します。しかし、私の最初のアプローチで何が間違っていますか?私は本当にここで問題を起こさない。

+0

新しいオブジェクト(){ public String text = "Something"; }) – GKislin

答えて

1

、コンストラクタコールのTestの型引数は(ダイヤモンド演算子を使用しているため)推測され、そしてそれは匿名と推定されるので

new Test<>(new Object(){ 
     public String text = "Something"; 
    }, (o) -> { 
     System.out.println(o.text); 
    }); 

はコンパイル最初の引数が評価される型(匿名クラス型)であるため、2番目の引数の型はoperation<that anonymous class type>です。コードの最初の部分で

、式

t.runOperation((o) -> { 
     System.out.println(o.text); // text cannot be resolved 
    }) 

はコンパイルされません。ここで、ラムダの型は、変数tの型に基づいて推測され、これはTest<?>である。したがって、runOperationの引数はoperation<some unknown type>である必要があります。ここで動作するrunOperationの唯一の引数はnullです。

1
Test<?> t = new Test<>(new Object(){ 
      public String text = "Something"; 
     }, (o) -> { 
      System.out.println(o.text); 
     }); 

ここコンパイラはあなたの匿名クラスとTestTを交換し、そのクラス以来、第二ケースが働く理由です変数textが含まれています。

+0

しかし、最初のケースでコンパイラがTを私の匿名クラスに置き換えるのはなぜですか? – ArcticLord

+0

ですが、あなたの匿名クラスの型は 'text'という名前のプロパティを持たない' Object'ですので、コンパイルエラーが発生します。 –

2

問題は、あなたの匿名クラスがまだいくつかの型に適合(拡張または実装)していて、選択した型がtextプロパティを持たないObjectです。いくつかの種類のプロパティを参照するには、実際のクラスまたはインターフェイスが必要です。そのため、コンパイラはオブジェクトで使用できるプロパティとメソッドについて保証します。

これは機能します。コードの第2部分において

public class Test<T> { 

    public static class Data { 
     public String text; 
    } 

    @FunctionalInterface 
    public interface Operation<K> { 
     void execute(K object); 
    } 

    private T obj; 
    private Operation<T> op; 

    public Test(T obj) { 
     this.obj = obj; 
    } 

    public void runOperation(Operation<T> op) { 
     op.execute(obj); 
    } 

    public static void main(String[] args) { 
     Test<Data> t = new Test<>(new Data() {{ 
      this.text = "Something"; 
     }}); 

     t.runOperation((o) -> { 
      System.out.println(o.text); 
     }); 
    } 
} 
関連する問題