使用通配符实例化泛型对象

3

我有一个类

public class OrderedBox<T> {}    

编译器不允许创建这样的成员/局部变量。
OrderedBox<? extends T> testItems1 = new OrderedBox<? extends T>();
List<? extends T> testItems2 = new ArrayList<? extends T>();

可以理解,因为在运行时,它不能保证插入的对象类型(上限为T),这会违反类型安全性。

但它允许创建像这样的成员/局部变量。 为什么和如何允许这样做?

private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();

注意: 我在阅读http://www.onjava.com/pub/a/onjava/excerpt/javaian5_chap04/index1.html时遇到了这个问题。
可能的重复问题: 使用通配符创建新的泛型对象 泛型通配符实例化 但是这两个问题都提供了编译失败的原因。 我不明白为什么和如何允许最后一个选项。

两个问题:你正在运行哪个版本的Java,为什么不使用钻石<>操作符来解决这个问题? - Makoto
在您提供的链接中,第一个答案“使用通配符创建新的泛型对象”解释了为什么第一次不允许(因为您没有说明testItems1对象将被创建为哪个类),以及为什么第二次允许(因为您说明了列表应该是OrderedBox类型)。 - Naresh Joshi
@Makoto,第一:Java7。第二:谢谢,<>解决了问题。但我的疑问是为什么它解决了问题? - arc
@NareshJoshi 但是OrderedBox的类型推断未指定。 - arc
是的,但是对于创建列表对象,您不需要它。对于列表对象的创建,您只需要存储在列表中的对象类型,即OrderedBox,但是同样的情况并不适用于您的第一个场景。 - Naresh Joshi
2个回答

5
这个「一行代码」的答案实际上在你发布的第二个SO问题中得到了解释:Generics wildcard instantiation 这个「一行代码」声明了一个类型为OrderedBox,但并没有创建它的实例。
private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();

这段话表明您将拥有一个OrderedBox,但并没有说明具体是哪个。 当您尝试创建实例时可能会遇到麻烦。

testItems.add(new OrderedBox<? extends T>())

因为在那个时候,你需要修正类型。

你的解释真的很有帮助。我尝试了一下,就像你说的那样,它起作用了。但是我想知道它在运行时是如何工作的 :)。正在编辑问题。 - arc
Java编译器执行“类型擦除”(这是要查找的关键字)。因此,在运行时,它会转换为OrderedBox<Object>,理论上您可以将任何内容放入其中。但编译器会在此之前阻止您这样做。 - Simon

0

你的列表对象是一个袋子,你可以在里面放很多有序盒子对象。

private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();

无论在编译时OrderedBox中有什么,使用这种语法将在尝试将对象插入列表时导致问题。

声明类时应该使用泛型(通配符),但在创建该类的对象时应该明确指定。

private List<OrderedBox<Object>> testItems = new ArrayList<OrderedBox<Object>>();

编译器不允许

OrderedBox<? extends T> testItems1 = new OrderedBox<? extends T>();

因为您在这里没有说明OrderedBox的类型,所以您也应该在此处具体说明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接