java泛型:通配符和子类 - 为什么会发生这种情况?

时间:2014-05-09 10:00:08

标签: java generics inheritance wildcard

我读了一些关于泛型,通配符和遗产的内容。但仍然无法弄清楚为什么在行getFoo()。doit(this); 有人可以解释为什么会发生这种情况,以及正确的方法是什么?

public class A<T> {
    private Foo<T, ? extends A<T>> foo;
    public Foo<T, ? extends A<T>> getFoo() {
        return foo;
    }
    public void setFoo(Foo<T, ? extends A<T>> foo) {
        this.foo = foo;
    }
}

public class B extends A<Integer>{
    public B() {
        setFoo(new Bar());
        getFoo().doit(this);
    }
}

public class Bar implements Foo<Integer, B> {
@Override
    public void doit(B a) {
        System.out.println("some process");
    }

}

public interface Foo<T, V extends A<T>> {
    public void doit(V a);
}

1 个答案:

答案 0 :(得分:0)

在方法调用中,您不允许将非空值作为通配符extends参数提供(在您的情况下为getFoo().doit(<? extends A<Integer> a))。原因是编译器无法知道原始通用定义是什么,因此它将拒绝编译代码。

您的问题可以用simle List<?>

来说明
public static List<Integer> myList = new ArrayList<Integer>();

public static List<? extends Number> getList() {
    return myList;
}

public static void main() {
    getList().add(Integer.valueOf(1000)); // Can not substitute wildcard by Integer 
}

上面的代码看起来完全正常(除了编译错误:)),但想象一下:

public static void main() {
    getList().add(Long.valueOf(1000)); // This would definitely cause ClassCastException later when someone calls myList.get(0)
}

更新要解决您的问题,您需要摆脱通配符,例如在类定义中添加另一个类型参数:

public class A<T, V extends A<T, V>> {
    private Foo<T, V> foo;
    public Foo<T, V> getFoo() {
        return foo;
    }
    public void setFoo(Foo<T, V> foo) {
        this.foo = foo;
    }
}

public class B extends A<Integer, B>{
    public B() {
        setFoo(new Bar());
        getFoo().doit(this);
    }
}