是否存在以下两种方式之间的区别:
<N extends Number> Collection<N> getThatCollection(Class<N> type)
并且
Collection<? extends Number> getThatCollection(Class<? extends Number>)
是否存在以下两种方式之间的区别:
<N extends Number> Collection<N> getThatCollection(Class<N> type)
并且
Collection<? extends Number> getThatCollection(Class<? extends Number>)
它们暴露不同的接口和方法契约。
第一个声明应该返回一个元素类型与参数类相同的集合。编译器会推断出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中强调应该避免在返回类型中使用有界通配符。虽然在某些情况下,在返回类型中使用有界通配符可能会有用,但是对于结果代码的丑陋程度来说,我认为这种利益应该被抵消。
Collection<? extends Number> getRoot(Class<? extends Number> number){
ArrayList<Integer> result=new ArrayList<Integer>();
result.add(java.util.Math.round(number);
return result)
}