有界通配符和类型参数有什么区别?

37

是否存在以下两种方式之间的区别:

<N extends Number> Collection<N> getThatCollection(Class<N> type)

并且

Collection<? extends Number> getThatCollection(Class<? extends Number>)
2个回答

38

它们暴露不同的接口和方法契约。

第一个声明应该返回一个元素类型与参数类相同的集合。编译器会推断出N的类型(如果没有指定的话)。因此,在使用第一个声明时,以下两个语句是有效的:

Collection<Integer> c1 = getThatCollection(Integer.class);
Collection<Double> c2 = getThatCollection(Double.class);
第二个声明没有声明返回的集合类型参数与参数类之间的关系。编译器假定它们是不相关的,因此客户端必须将返回的类型用作 Collection<? extends Number>,而不管参数是什么:
// Invalid statements
Collection<Integer> c1 = getThatCollection(Integer.class);   // invalid
Collection<Double> c2 = getThatCollection(Double.class);   // invalid
Collection<Number> cN = getThatCollection(Number.class);   // invalid

// Valid statements
Collection<? extends Number> c3 = getThatCollection(Integer.class);  // valid
Collection<? extends Number> c4 = getThatCollection(Double.class);  // valid
Collection<? extends Number> cNC = getThatCollection(Number.class);  // valid

建议

如果返回类型参数和传递的参数确实存在关联,则最好使用第一个声明。如上所述,客户端代码更清晰。

如果不存在关联,则仍然最好避免使用第二个声明。具有有界通配符返回类型会强制客户端在任何地方使用通配符,因此客户端代码变得混乱且难以阅读。Joshua Bloch在幻灯片23中强调应该避免在返回类型中使用有界通配符。虽然在某些情况下,在返回类型中使用有界通配符可能会有用,但是对于结果代码的丑陋程度来说,我认为这种利益应该被抵消。


3
感谢您的委托,我将尽力为您提供准确、通俗易懂的翻译。以下是需要翻译的内容:+1 for a clear explanation of the differences. Minor quibble - I think you go too far in assuming the first is always the better choice - I'd say "needless to say" the better choice would depend on context.对于明确解释它们之间差异的方式,我给予点赞。小小的提议——我认为您过于假设第一个选项总是更好的选择——我会说,“不用说”,更好的选择是取决于上下文的。 - Steve B.
@Steve 谢谢!我添加了一个解释,为什么应该避免第二个语句。 - notnoop

-3
在这种特定情况下,不需要。但第二个选项更加灵活,因为它允许您返回一个包含不同类型元素(即使它们也是数字)的集合,而不是与集合参数相同类型的元素。
具体例子:
Collection<? extends Number> getRoot(Class<? extends Number> number){ 
    ArrayList<Integer> result=new ArrayList<Integer>();
    result.add(java.util.Math.round(number); 
    return result) 
}

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