Generic FunctionalInterface和Method Reference由Type Erasure搞砸了

时间:2015-05-05 21:00:26

标签: java generics java-8 type-erasure functional-interface

我有以下通用的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()方法?

在我的后代课堂上似乎有类似擦除的时髦,但是什么?这是一个错误吗?我做过不支持的事吗?

2 个答案:

答案 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();

它将摆脱编译器错误。