我反复发现,上界通配符relaxes the restrictions of types that a type parameter can accept.也适用于有界泛型,例如:
static <T extends Number> void gMethod (ArrayList <T> list) {}
此方法的泛型将在指定时接受Number类型的对象或其任何子类:
ArrayList <Integer> intList = new ArrayList();
gMethod(intList); // allowed
为进一步说明,绑定到Number的泛型将接受Number或其任何子类的类型参数:
class Thing <T extends Number> {}
Thing <Number> numThing = new Thing();
Thing <Integer> intThing = new Thing();
Thing <Double> dubThing = new Thing(); // All three instances work
鉴于此,我可以看到使用上界通配符与有界泛型的唯一好处是可以声明上界通配符类型参数,而无需依赖类或方法已经声明的类型参数。我还缺少更重要的好处吗?
答案 0 :(得分:0)
„ …我可以看到使用上界通配符和有界泛型的唯一好处……”
如果您的用例一次只需要您一次使用一个 Thing
,那么您所需要的简单使用场景就是您所需要的。
但是最终,您将获得一个用例,其中需要使用 Things
的不同种类。那时,您需要从工具箱中提取一些更高级的多态性。
„ ...我还缺少更重要的好处吗?... ”
听起来您失踪的一个超级重要好处是类型之间的可替换性关系。称为covariance。
例如,由于这样做是合法的:
Integer[] intAry = {2,4,6,8};
Number[] numAry = intAry;
然后直观地看来,您应该能够做到这一点:
List<Integer> intList = List.of(8,6,7,5,3,0,9);
List<Number> numList = intList; // but this fails to compile
具有上限的通配符有效地使集合成为协变的:
List <? extends Number> numList = intList;
由于 Integer
扩展了 Number
:
Thing<Number> numThing = new Thing<>();
Thing<Integer> intThing = new Thing<>();
然后直观地看来,您应该能够做到这一点:
numThing = intThing; // but this fails to compile
具有上限的通配符有效地使 Things
更直观:
Thing<? extends Number> numThing = new Thing<>();
numThing = intThing; /* That makes sense! */
处理方法相同。有了这个声明:
public static void use(Thing<Number> oneThing){
/*...*/
}
这将无法编译:
Thing<Integer> intThing = new Thing<>();
use(intThing); /* error: no suitable method found for use(Thing<Integer>) */
带有上限的通配符可以使用 Things
,就像您凭直觉认为的那样:
public static void use(Thing<? extends Number> anyThing){
/* ...*/
}
...
Thing<Integer> intThing = new Thing<>();
use(intThing); /* Perfectly fine! */
„ …适用于有界的泛型…此方法的泛型将接受…上界通配符与有界的泛型…< / em>“
您错误地称为“ 泛型 ”的东西实际上称为type parameters,type variables或type arguments;取决于the context。