4

我有以下通用功能接口:

@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. 原始类型是这样说的:

原始类型的超类(分别为超接口)是泛型类型的任何参数化的超类(超接口)的擦除。

这意味着一个 rawFooList只是一个 rawArrayList并且该方法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)

“修复”它的一种方法是做一些棘手的事情,如下所示:

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 回答