Java泛型 - 带有“extends”类型集合参数的方法拒绝有效参数?

时间:2015-10-30 12:48:08

标签: java generics

我试图理解为什么编译器拒绝/接受以下参数。

我假设两个参数都被接受,因为两个集合什么都不包含,但是Serializable的子节点。
并且成为Serializable的孩子 - 是唯一一个由方法签名强制执行的东西 D extends Serializable - 对吧?

为什么接受 D类型的Set serializables1扩展Serializable
为什么Set serializables2的类型为?扩展Serializable 被拒绝?
为什么 D扩展Serializable ? extends Serializable 在这里不一样了吗?

public class GenTest<D extends Serializable> {
    Set<D> serializables1;
    Set<? extends Serializable> serializables2;

    public static void main(String[] args) {
        GenTest<Serializable> g = null;

        g.accept(g.serializables1); // OK - WHY?
        g.accept(g.serializables2); // NOT OK - WHY?
    }

    void accept(Set<D> serializables) {}
}

4 个答案:

答案 0 :(得分:3)

根据签名,.accept()方法使用类范围的D类型参数:

void accept(Set<D> serializables) {}

GenTest实例化为GenTest<Serializable> g = null;意味着D将在运行时被Serializable替换。

现在,Set<? extends Serializable> serializables2是什么意思?

这意味着可以为serializables2分配Set未知Serializable子类。编译器没有证据表明此 unknown 子类在运行时将匹配D的替换,因此拒绝允许代码编译。

假设您有以下两种类型:

class A implements Serializable { }

class B implements Serializable { }

Set<? extends Serializable> serializables2表示serializables2可以在运行时分配Set<A>或分配Set<B>。我们假设它已分配Set<B>

现在,如果您的g.serializables仅包含A类型的对象(这是可能的,因为D已替换为Serializable),这意味着在运行时您获得ClassCastException时,尝试将Set<B>传递给方法时,应提供Set<A>

更多信息:

答案 1 :(得分:0)

使用? extends Serializable时,它可以是实现Serializable而不仅仅是D的任何类的对象,因此它不起作用。

答案 2 :(得分:0)

Set<? extends Serializable>确切地说该集合包含一个继承Serializable但不知道的类型,因此您对预仿制日具有一种向后兼容性而无法更改集合 - 并且你的编译器不知道你的例子中?是否符合D,所以他禁止给定用法。

答案 3 :(得分:0)

serializables1包含一组&#34; D&#34;,accept()接受一组&#34; D&#34;。 D的类型层次结构并不重要。 serializables2可以是任何Serializable。无法投射到D。