4

次の汎用 FunctionalInterface があります。

@FunctionalInterface
public interface FooInterface<T> {
    void bar(T arg);
}

そして、この ArrayList の子孫:

public class FooList<T> extends ArrayList<FooInterface<T>> {
    public void doFoo(T arg) {
        for(Iterator<FooInterface<T>> i = iterator(); i.hasNext(); ) {
            i.next().bar(arg);
        }
    }
}

ここで、メソッド参照と型消去を使用して次のコードを記述します。

protected void doFoo(Object arg) { }

private void doStuff() {                                         
    FooInterface f = this::doFoo; 

    List<FooInterface> list = new ArrayList<>();
    list.add(f2);                 
    list.add(this::doFoo);        

    FooList list2 = new FooList();
    list2.add(f2);                
    list2.add(this::doFoo);    // <-- Compiler chokes here, complaining that this is not a FunctionalInterface
}                                        

これは私を困惑させます。this::doFoo を FooInterface 変数に割り当て、コードの最初の部分で List.add() を呼び出しても、ArrayList から派生したクラスから同じ add() メソッドを呼び出すことを拒否するだけで、コンパイラが問題ないのはなぜですか。 ?

私の子孫クラスの型消去で何かおかしなことが起こっているようですが、何ですか? これはバグですか?サポートされていないことをしましたか?

4

2 に答える 2

4

FooList(型引数なし) は生の型と呼ばれます。4.8. Raw タイプは次のように述べています。

生の型のスーパークラス (それぞれ、スーパーインターフェイス) は、ジェネリック型のパラメーター化のいずれかのスーパークラス (スーパーインターフェイス) の消去です。

これは、 rawFooListは単なる rawArrayListであり、メソッドaddは を受け入れることを意味しますObject

Object関数型インターフェースではないため、ラムダのターゲットにすることはできません。これはどちらも機能しません:

Object f = this::doFoo;

完全なコンパイラ エラーは、多かれ少なかれこれらすべてを裏付けています。

error: no suitable method found for add(this::doFoo)
    list2.add(this::doFoo);    // <-- Compiler chokes here, complaining that this is not a FunctionalInterface
         ^
    method Collection.add(Object) is not applicable
      (argument mismatch; Object is not a functional interface)

それを「修正」する1つの方法は、次のようなトリッキーなことをすることです:

public class FooList<T> extends ArrayList<FooInterface<T>> {
    @Override
    public boolean add(FooInterface<T> e) {
        return super.add(e);
    }
    ...
}

ここでの実際の解決策は、生の型を使用しないことですが、「消去」について言及しているため、これをある程度認識しているようです。生の型を使用する理由はありません。

于 2015-05-05T21:38:34.900 に答える
0

FooList をパラメータ化する必要があります。変えたら

FooList list2 = new FooList();

FooList<FooInterface> list2 = new FooList();

コンパイラエラーを取り除きます。

于 2015-05-05T21:38:53.930 に答える