我试图理解为什么编译器拒绝/接受以下参数。
我假设两个参数都被接受,因为两个集合什么都不包含,但是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) {}
}
答案 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。