我有以下通用的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);
}
}
}
现在,我使用方法引用编写此代码并输入erasure:
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
}
这令我感到困惑。为什么编译器可以将我的:: doFoo分配给FooInterface变量,并在代码的第一部分调用List.add(),只是拒绝从ArrayList的类中调用相同的add()方法?
在我的后代课堂上似乎有类似擦除的时髦,但是什么?这是一个错误吗?我做过不支持的事吗?
答案 0 :(得分:4)
FooList
(没有类型参数)被称为原始类型。 4.8. Raw Types说:
原始类型的超类(分别是超级接口)是泛型类型的任何参数化的超类(超接口)的擦除。
这意味着原始FooList
只是原始ArrayList
,方法add
接受Object
。
由于Object
不是功能接口,因此它不能成为lambda的目标。这也行不通:
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)
解决问题的一种方法&#34;这是通过做一些棘手的事情,如下所示:
public class FooList<T> extends ArrayList<FooInterface<T>> {
@Override
public boolean add(FooInterface<T> e) {
return super.add(e);
}
...
}
这里的解决方案真的是not use raw types,但是因为你提到了擦除&#39;看起来你在某种程度上意识到了这一点。没有理由使用原始类型。
答案 1 :(得分:0)
您需要参数化FooList。如果你改变了
FooList list2 = new FooList();
到
FooList<FooInterface> list2 = new FooList();
它将摆脱编译器错误。