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

两者之间是否有区别

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

Collection<? extends Number> getThatCollection(Class<? extends Number>)

答案 1

它们公开了方法的不同接口和协定。

第一个声明应返回其元素类型与参数类相同的集合。编译器推断的类型(如果未指定)。因此,以下两个语句在使用第一个声明时是有效的: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)。虽然在某些情况下,返回类型中的有界通配符可能很有用,但恕我直言,结果代码的丑陋应该覆盖好处。


答案 2

在这种特殊情况下,不可以。但是,第二个选项更灵活,因为它允许您返回包含与集合参数所包含的类型不同的类型(即使它也是 Number)的元素的集合。

具体示例:

Collection<? extends Number> getRoot(Class<? extends Number> number){ 
    ArrayList<Integer> result=new ArrayList<Integer>();
    result.add(java.util.Math.round(number); 
    return result) 
}

推荐