【问题标题】:Why are the angle brackets before the return type omitted sometimes from the definition of a generic method为什么在泛型方法的定义中有时会省略返回类型之前的尖括号
【发布时间】:2014-08-30 18:33:25
【问题描述】:

我正在阅读有关泛型的 Effective Java 第 5 章,特别是有关首选泛型方法的项目。我注意到有时在返回类型之前的方法声明中的类型参数(尖括号之间)有时会被省略。这样的例子很多,比如第二版第135页:

public void popAll(Collection<E> dst) {
while (!isEmpty())
dst.add(pop());
} 

另一方面,我在声明中看到了类似的泛型方法

public <E> void ...

第一个是错字吗?如果不是,我什么时候可以在声明中省略括号?

谢谢

【问题讨论】:

  • 我不知道为什么这被标记为重复。所谓的欺骗是一个完全不同的问题。
  • 由于我不能发布一个合法的答案,我会用评论来回答:我相信不同之处在于,在第一种情况下,整个类被声明为泛型,而在第二种情况下,只有方法是通用的。
  • 投票也重新开放。我无法从另一个问题中弄清楚。看起来相关,但不重复。

标签: java generics effective-java


【解决方案1】:

E 是一个类型变量——它代表一些其他类型,例如StringInteger。因此,正如您在不知道 dst 的定义位置和方式的情况下无法理解 dst.add(pop()) 一样,如果不知道类型变量 E 的定义位置和方式,您也无法理解像 popAll(Collection&lt;E&gt; dst) 这样的方法声明。在popAll 的情况下,类型变量E 在类级别定义:Stack&lt;E&gt;:它是堆栈中元素的类型。你甚至会经常看到 javadoc'd:

/**A Stack of elements
  *
  *@param E The type of elements in the stack */
public class Stack<E>{
    public void popAll(Collection<E> dst){ ... }
}

另一方面,当您看到像 public &lt;E&gt; void ... 这样的方法声明时,类型变量 E 正在被声明(不是从某个封闭范围中引用,例如封闭类)。事实上,大多数时候当你看到一个方法有自己的类型变量时,它是一个静态方法,所以没有封闭类的实例来建立E的值。

在这两种情况下,E 类型变量在做什么?它告诉我们两种不同的类型必须如何相互关联。在popAll 中,它告诉我们要放入弹出元素的集合的元素类型必须与要从中弹出它们的堆栈的元素类型相匹配。

同样,以第 136 页为例:

public class ListUtils{
    public static <E> E reduce(List<E> list, Function<E> f, E initVal);
}

这里,E 类型变量告诉我们list 的元素类型必须匹配f 的参数类型和initVal 的类型。外围类没有为我们定义E,它只在reduce方法声明的范围内有意义。

【讨论】:

    【解决方案2】:

    不同之处在于,在第一种情况下,整个类被声明为泛型,而在第二种情况下,只有方法是泛型的。

    【讨论】:

      【解决方案3】:

      答案是……不是。 “通用方法”定义是在返回类型之前声明类型变量的方法:

      一个方法是通用,如果它声明了一个或多个类型变量。 (JLS 8.4.4)

      因此,popAll 不是“通用方法”。

      由于该方法没有声明类型参数E,所以必须在封闭范围内定义;几乎可以肯定的是包含该方法的类(“泛型类”)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-14
        • 1970-01-01
        • 1970-01-01
        • 2011-06-20
        • 2021-08-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多