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

rre*_*jex 37 java generics type-parameter bounded-wildcard

两者之间有区别吗?

<N extends Number> Collection<N> getThatCollection(Class<N> type)
Run Code Online (Sandbox Code Playgroud)

Collection<? extends Number> getThatCollection(Class<? extends Number>)
Run Code Online (Sandbox Code Playgroud)

not*_*oop 36

它们暴露了该方法的不同接口和契约.

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

Collection<Integer> c1 = getThatCollection(Integer.class);
Collection<Double> c2 = getThatCollection(Double.class);
Run Code Online (Sandbox Code Playgroud)

第二个声明不声明返回的Collection类型参数与参数类之间的关系.编译器假定它们是不相关的,因此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
Run Code Online (Sandbox Code Playgroud)

建议

如果确实返回的类型参数和传递的参数之间存在类型关系,那么使用第一个声明要好得多.如上所述,客户端代码更清晰.

如果关系不存在,那么最好避免第二次声明.具有有界通配符的返回类型会强制客户端在任何地方使用通配符,因此客户端代码会变得咔嗒咔嗒而且不可读.Joshua Bloch强调你应该避免返回类型中的有界通配符(幻灯片23).虽然返回类型中有界通配符可能有用,但在某些情况下,结果代码的丑陋应该恕我直言.

  • +1可以清楚地解释差异.轻微的狡辩 - 我认为你走得太远,假设第一个总是更好的选择 - 我会说"不用说"更好的选择取决于背景. (3认同)