我正在阅读Gilad Bracha撰写的“Java编程语言中的泛型”,我对一种声明风格感到困惑。以下代码位于第8页:
interface Collection<E>
{
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
interface Collection<E>
{
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
// hey, type variables can have bounds too!
}
我的困惑来自第二次宣言。我不清楚<T>
声明在以下行中的用途是什么:
public <T> boolean containsAll(Collection<T> c);
该方法已经有一个与之关联的类型(布尔值)。
为什么要使用<T>
以及它对编码器有什么作用?
我认为我的问题需要更具体一些。
你为什么要写:
public <T> boolean containsAll(Collection<T> c);
VS
public boolean containsAll(Collection<T> c);
我不清楚在{contains}的第一个声明中<T>
的目的是什么。
答案 0 :(得分:3)
该方法已经有一个与之关联的类型(布尔值)。
这是 return 类型。该方法的完整类型是“采用Collection<T>
(对于某些T
)参数并返回boolean
”的方法。
这就是T
的用武之地:函数的参数使用它。换句话说,可以使用不同类型作为参数调用此方法。这些类型的唯一限制是它们必须实现Collection<T>
接口,它本身依赖于泛型参数T
(存储在集合中的对象的类型)。
答案 1 :(得分:3)
据我所知,在这种情况下<T>
根本没有提供任何有用的东西。它创建的方法在功能上完全等同于使用通配符的方法。
以下是 有用的几个示例:
public List<?> transform(List<?> in);
//vs
public <T> List<T> transform(List<T> in);
在上面,您可以将返回类型与输入类型相关联。第一个示例无法关联两个通配符的运行时类型。
public void add(List<?> list, Object obj);
//vs
public <T> void add(List<? super T> list, T obj);
在上文中,第一种方法甚至无法将obj
添加到list
,因为它不能被视为类型安全。第二个中的泛型参数确保list
可以保存obj
所属的任何类型。
答案 2 :(得分:2)
?只是一个通配符。这意味着该方法将接受任何类型的Collection。
<T>
是方法的类型参数。它实质上是为通配符分配一个名称,然后可以在方法声明和定义的其他地方引用该名称。
如果方法的返回类型根据传入的类型而有所不同,则可以更好地说明差异。
假设你开始使用类似
的方法 Object getRandomElement( Collection<?> c )
这将接受任何Collection,但无法约束其返回类型。因此调用者必须将结果转换回它预期的任何类型 - 这应该可行,但会引发不安全的类型转换警告。
使用类型参数,您可以改为编写
<T> T getRandomElement( Collection<T> c )
在这种情况下,如果使用Collection<String>
调用此方法,编译器将知道它将返回String
。
答案 3 :(得分:1)
<T>
(在方法声明中,返回类型之前)是泛型类型声明。您可以定义要在方法中使用的新泛型类型:http://download.oracle.com/javase/tutorial/java/generics/genmethods.html
答案 4 :(得分:0)
尝试在没有<T>
的情况下进行编译。
基本上,它告诉编译器这个方法包含一个泛型。在第一个例子中不需要它,因为?是一种特殊情况,第二种方法是引用接口本身定义的类型。
在不相关的注释中,接口中不需要公共。默认情况下,界面中的方法是公共的,因此可以节省一些输入。
答案 5 :(得分:0)
它声明了方法使用的泛型类型T
。虽然泛型类型E
对于整个接口T
是相同的,但仅限于声明它的方法。