问题描述
|
我今天遇到了一个有趣的问题。考虑以下代码
public static class Parent {}
public static class Child extends Parent {}
Set<Child> childs = new HashSet();
Set<Parent> parents = (Set<Parent>)childs; //Error: inconvertible types
Parent parent = (Parent)new Child(); //works?!
为什么这样的演员不能奏效?我期望由于泛型的各种规则,隐式强制转换将不起作用,但是为什么显式强制转换不能起作用?
解决方法
强制转换无效,因为Java泛型不是协变的。
如果编译器允许这样做:
List<Child> children = new ArrayList();
List<Parent> parents = (List<Parent>)children;
那么在这种情况下会发生什么呢?
parents.add(new Parent());
Child c = children.get(0);
最后一行将尝试将Parent
分配给Child
—但是Parent
不是Child
!
所有Child
都是Parent
(因为Child extends Parent
起),但所有Parent
都不是Child
。
, Set<Parent>
可以包含Parent
的任何子类。 Set<Child>
可以包含Child
的任何子类。因此,不允许一个Parent
的子类,而不是一个Child
的子类,但不允许另一个,这使它们成为不兼容的类型。
, 因为一组孩子不是一组父母。定义通用(参数化)集实际上与定义新类相同,因此您要定义两个不相交的类。
, 不过,泛型的超级类型的工作方式略有不同:
Set<Child> childs = new HashSet();
Set<? extends Parent> parents = childs;
Set是Set和Set的超级类型
我建议您阅读有关泛型的文档,以了解泛型容器之间没有继承,只是因为它不是继承。继承首先意味着专业化。想想一个用来盛放动物的盒子,好吧,它可以由只包含老虎的盒子派生而来,但这当然意味着盒子可以对老虎起作用,但是也可以做所有超类型的事情,包括养蜂。所有动物的盒子。人类要同时考虑两种分类法是一件很麻烦的事情:高位尼克层级(专业化,继承)和代名词层级(容器/包含)。
在最后一行中,无需强制转换:
Parent parent = new Child();
斯特凡