【问题标题】:Java Generics WildCard: <? extends Number> vs <T extends Number>Java 泛型通配符:<?扩展号码> vs <T 扩展号码>
【发布时间】:2012-07-16 01:05:14
【问题描述】:

这两个函数有什么区别?

static void gPrint(List<? extends Number> l) {
    for (Number n : l) {
        System.out.println(n);
    }
}

static <T extends Number> void gPrintA(List<T> l) {
    for (Number n : l) {
        System.out.println(n);
    }
}

我看到相同的输出。

【问题讨论】:

  • 也许是因为没有区别?
  • 为什么我们不能定义类名 extends Number> 但 class Name 没问题?
  • @PrateekJoshi 是的,我也是这么想的。你得到答案了吗?

标签: java generics


【解决方案1】:

在这种情况下没有区别,因为T 再也不会被使用了。

声明T的原因是为了可以再次引用它,从而将两个参数类型,或者一个返回类型绑定在一起。

【讨论】:

  • 同意!那么是否存在只有“?”的情况将为我完成这项工作,但不是“T”。或者通配符可以完成的任何事情都可以使用“T”完成?
  • 如果?只有一个,则等价。如果有多个?,那么您必须使用T?,这取决于您是否需要两种类型相同,或者允许它们不同。如果你有一个方法x(&lt;? extends Number&gt; a, &lt;? extends Number&gt; b),你可以用一个整数和一个长整型来调用它。如果您有T a, T b,则它们必须是同一类型。
  • 但我仍然可以做到 x(T a, U b)。那么哪个是首选方式?是否倾向于不使用通配符(尽可能)?
  • 这只是风格问题。我更喜欢通配符,以明确该类型未绑定到另一种类型。
【解决方案2】:

不同之处在于使用通配符时不能引用T

你现在不在,所以“没有区别”,但这里是你可以如何使用 T 来有所作为:

static <T extends Number> T getElement(List<T> l) {
    for (T t : l) {
        if (some condition)
            return t;
    }
    return null;
}

这将返回 与传入的任何内容相同的类型。例如,它们都将编译:

Integer x = getElement(integerList);
Float y = getElement(floatList);

【讨论】:

  • 那么什么时候真正需要通配符?
  • 通配符并不是真正“需要”的,但是当它确实是一个未绑定的类型(不需要给它命名)时,它可以减少输入。结果代码是等效的。这类似于int a = 1; return areturn 1 之间的区别。或者写&lt;T extends Object&gt;而不是&lt;T&gt;
  • @Bohemian 等一下,那个代码怎么正确?是不是在运行时发生类型擦除,导致代码在运行时失败?
  • @Dr.Java 是和否。是的,有运行时类型擦除,但运行时没有错误,因为在编译时类型是推断并且类型安全得到保证。见Type Inference
【解决方案3】:

T 是有界类型,即无论您使用什么类型,您都必须坚持使用扩展 Number 的特定类型,例如如果将Double 类型传递给列表,则不能将Short 类型传递给它,因为TDouble 类型,并且列表已经受该类型的限制。相反,如果您使用? (wildcard),则可以使用扩展Number 的“任何”类型(将ShortDouble 添加到该列表中)。

【讨论】:

    【解决方案4】:

    当您使用 T 时,您可以对 List 执行所有类型的操作。但是使用的时候不能添加。

    T - 与具有完全访问权限的对象引用相同
    ? - 提供部分访问权限

    static void gPrint(List<? extends Number> l) {
     l.add(1); //Will give error
    for (Number n : l) {
        System.out.println(n);
    }
    
    static <T extends Number> void gPrintA(List<T> l) {
    l.add((T)1); //We can add
    for (Number n : l) {
        System.out.println(n);
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-30
      • 2021-12-18
      • 1970-01-01
      • 2010-10-19
      • 2023-02-02
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 2014-10-24
      相关资源
      最近更新 更多