这里有一个快速的通用类,使这个问题更容易理解。您可以根据需要假装它“装箱”一个值。
public class Box<T> { }
现在,在我的main
方法中,我可以这样做:
Box b1 = new Box<>();
Box<?> b2 = b1;
Box b3 = b2;
因此,我很清楚,可以将使用通配符参数化的原始Box
和Box
都转换为彼此的类型。
Object box = (Box<?>)(Box) (Box<?>)(Box) ... new Box<>();// Valid (without the ellipsis)
那么为什么,我的List
原始框不能转换为List
的通配符框,反之亦然吗? (如果找到以下代码,则所有与编译错误有关的文档都可以找到。)
List<Box> rawBoxes = new LinkedList<>();
List<Box<?>> wildcardBoxes = new LinkedList<>();
Object o1 = (List<Box<?>>) rawBoxes;// Cannot cast from List<Box> to List<Box<?>>
Object o2 = (List<Box>) wildcardBoxes;// Cannot cast from List<Box<?>> to List<Box>
“无法从List<Box>
投射到List<Box<?>>
”,反之亦然...
我猜想有人会尝试提出List<Dog>
无法转换为List<Animal>
的事实,反之亦然。但是,这样做的原因是:
List<Animal> animals = new LinkedList<>();
animals.add(new Cat());
Dog dog = ((List<Dog>) animals).get(0);
Dog
的列表不是不是Animal
的列表,因为它只能包含Dog
。
使用List<Box>
和List<Box<?>>
,可以将任何一种Box
放入其中一个:
List<Box> rawBoxes = new LinkedList<>();
List<Box<?>> wildcardBoxes = new LinkedList<>();
Box rawBox = new Box<>();
Box<?> wildcardBox = new Box<>();
Box<String> stringBox = new Box<>();
// They can both take raw boxes
rawBoxes.add(rawBox);
wildcardBoxes.add(rawBox);
// They can both take wildcard boxes
rawBoxes.add(wildcardBox);
wildcardBoxes.add(wildcardBox);
// They can both take boxes storing arbitrary stuff
rawBoxes.add(stringBox);
wildcardBoxes.add(stringBox);
This出现了,这告诉我,如果Java允许的话,这样的强制转换是安全的。我想知道的是为什么不允许从List<Box>
到List<Box<?>>
的投射,以及如何从{{ 1}}。
如果还有一个问题可以完全回答这两个问题,请将其标记为重复。我自己搜索答案时不知道要查找什么。