Java泛型中的<?>和<? extends Object>有什么区别?

114

我以前见过通配符用来表示任何对象 - 但最近看到了这样的用法:

<? extends Object>

所有对象都是继承自 Object 类,那么这两种用法是否同义呢?


2
这是一样的东西。请参见https://dev59.com/Y3E95IYBdhLWcg3wheRR - Dan
4
如果您在那个问题中搜索“? extends Object”,您将找不到任何内容。我正在阅读答案,看看能否推断出任何信息,但我认为这不是关于泛型的。 - orbfish
@Dan - 这是一个不同的问题。我之前看过这个问题,记得至少提到了一个微妙的区别。让我看看能否找到它... - Paul Bellora
1
这里可能是Java中的无界通配符的重复问题(甚至包括了Kevin Bourrillion的错误答案)。 - Paul Bellora
@KublaiKhan 嗯,被采纳的答案讲述了为什么不应该使用这种语法,而不是你为什么要使用它,所以我觉得它并不令人满意。notnoop的回答提供了很好的信息,但我很好奇可重构性如何影响在这种情况下的使用。如果有人能明确这一点,他们就会得到我的赞同,并使这个问题成为一个独特的问题 ;) - orbfish
显示剩余2条评论
3个回答

118
<?><? extends Object>是同义词,这一点可以预料到。
在泛型中有几种情况下,extends Object实际上并不是多余的。例如,<T extends Object & Foo>将导致T在擦除时变成Object,而使用<T extends Foo>则会在擦除时变成Foo。(如果你试图保持与使用Object的旧版API的兼容性,则这可能很重要。)
来源:http://download.oracle.com/javase/tutorial/extra/generics/convert.html;它解释了JDK的java.util.Collections类为什么有一个具有此签名的方法。
public static <T extends Object & Comparable<? super T>> T max(
    Collection<? extends T> coll
)

4
我不清楚这个例子是如何相关的,因为它既没有使用 <?> 也没有使用 <? extends Object。 - orbfish
31
它只是与我认为你会觉得有趣相关,因为这是一个extends Object实际上有意义的例子。如果我错了,那么我道歉。希望它至少对其他遇到你问题的人有所帮助。 - ruakh
@ruakh - 对于有界通配符比类型参数更感兴趣,但是至少你回答了问题。 - orbfish
1
你应该在最开始的帖子中说明这一点。这样,他的回答就能更贴切地回应你的问题了。 - liltitus27

21

尽管 <?> 被认为是 <? extend object> 的简写,但两者之间存在微小的差异。 <?> 是可实例化的,而 <? extend object> 不是。他们这样做的原因是为了更容易区分可实例化类型。任何看起来像 <? extends something><T><Integer> 的东西都是不可实例化的。

例如,下面的代码可以正常工作:

List aList = new ArrayList<>();
boolean instanceTest = aList instanceof List<?>;

但是这会产生一个错误

List aList = new ArrayList<>();
boolean instancetest = aList instanceof List<? extends Object>;

了解更多信息,请阅读 Maurice Naftalin 编写的《Java 泛型与集合》。


List<?> 怎么能被实例化,如果编译器会将其转换为 List<Object>,因此关于 ? 的类型信息就丢失了呢? - Trismegistos
我认为 <?> 更多地设计用于向后兼容传统API,以区别于 Java 5 之后的代码中的 <Object> 和 <? extends Object>。 - Dennis C

15

<?><? extends Object>的简写形式。您可以阅读下面分享的链接以了解更多详情。


<?>

"?"代表任何未知类型,它可以在代码中表示任何类型。如果您不确定类型,请使用该通配符。请注意保留HTML标签。
ArrayList<?> unknownList = new ArrayList<Number>(); //can accept of type Number
unknownList = new ArrayList<Float>(); //Float is of type Number

注意: <?> 表示任何东西。所以它可以接受从Object类未继承的类型。

<? extends Object>

<? extends Object>表示您可以传递一个Object或扩展Object类的子类。

ArrayList<? extends Number> numberList = new ArrayList<Number>(); //Number of subclass
numberList = new ArrayList<Integer>(); //Integer extends Number
numberList = new ArrayList<Float>(); // Float extends Number 

enter image description here

T - 用于表示类型
E - 用于表示元素
K - 键
V - 值
N - 表示数字
参考链接:

enter image description here


1
因此,它可以接受未从Object类继承的类型,但所有Java类都是从Object类继承或隐式继承的。 - hackjutsu

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