9

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

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

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

public <E> void ...

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

谢谢

4

3 回答 3

5

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

于 2014-09-01T00:39:46.463 回答
5

E是一个类型变量——它代表一些其他类型,比如Stringor Integer。因此,就像dst.add(pop())不知道在何处以及如何dst定义的情况下无法理解一样,您也无法理解方法声明,就像popAll(Collection<E> dst)不知道类型变量在何处以及如何E定义的情况下一样。在 的情况下popAll,类型变量E是在类级别定义的Stack<E>::它是堆栈中元素的类型。你甚至会经常看到它是 javadoc 的:

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

另一方面,当您看到类似 的方法声明时public <E> 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方法声明的范围内有意义。

于 2014-09-01T02:14:14.880 回答
1

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

如果一个方法声明了一个或多个类型变量,那么它就是泛型的。( JLS 8.4.4 )

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

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

于 2014-09-01T06:10:29.627 回答