【问题标题】:What is the benefit of an upper bounded wildcard?上限通配符有什么好处?
【发布时间】:2019-11-27 17:33:18
【问题描述】:

我发现反复出现的解释是上限通配符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

鉴于此,我可以看到使用上限通配符与有界泛型的唯一好处是,可以在不依赖已由类或方法声明的类型参数的情况下声明上限通配符类型参数。我还缺少什么更重要的好处吗?

【问题讨论】:

  • 你没有展示任何有界通配符的例子......
  • 是的,它只是一个您不想麻烦命名的参数。无需发明一个只会使用一次的名称。
  • 如果有人想知道,这似乎是使用通配符的主要好处(如果不是唯一的话)。我只是碰巧在弄乱上限通配符时遇到了这个问题
  • 我看到了更多原因,但我不确定它们是否算作答案。 1)这取决于你想用这个list做什么。如果这是通配符,你能把东西放进去吗? 2)如果你真的不关心T(我的意思是你不会在方法内部使用任何变量作为T类型),那么有一个一般性的建议是摆脱它并使用wildcard 3)通配符可以有一个单一的界限,而类型引用可以有更多(当原始/擦除类型派生时这件事)4)当我已经有一个类型参数并且没有时,我发现自己可以引入通配符想要
  • 介绍另一个。例如:public &lt;T extends CoolInterface&gt; void(List&lt;? extends T&gt;)。我可以使用List&lt;R extends T&gt;,但这意味着我需要再引入一个类型参数,这可能对调用者来说意义不大。如前所述,我真的不知道这是否能回答您的问题。

标签: java generics wildcard bounded-wildcard


【解决方案1】:

...我可以看到使用上限通配符与有界泛型的唯一好处...

如果您的用例只要求您一次使用一个 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! */

...适用于有界 generics...此方法的 generic 将接受...上限通配符与有界 generic...“

您错误地称为“泛型”的东西实际上被称为type parameterstype variablestype arguments;取决于the context

【讨论】:

  • 我的问题应该更清楚。我的问题与方法签名中类型参数的功能有关,这些示例都没有解决我的问题。我正在将具有有界通配符的类型参数的参数化方法参数的函数与具有有界类型参数的类型参数的参数化方法参数的函数进行比较。在您的上一个代码 sn-p 中,您可以用有界类型参数替换有界通配符,并且边界相同,结果将是相同的。除了通配符的简洁性之外,一个似乎没有任何优势
  • ...除了通配符的简洁性之外,似乎没有任何优势比另一个...“ -​​ 如果你这么说,首席。
  • 如果您认为有好处,请随时分享。但是,我认为您不了解协方差是什么。通配符和类型参数都以相同的方式实现协方差,通配符和类型参数在方差方面的唯一区别是通配符也是逆变的,因此它们是双变量的。不过不用担心,泛型通常会让人困惑,我相信你会掌握它的窍门
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
相关资源
最近更新 更多