有人能解释一下这些java泛型方法的声明吗?
我正在阅读Gilad Bracha的《Java编程语言中的泛型》,我对声明的风格感到困惑。第8页有以下代码:有人能解释一下这些java泛型方法的声明吗?,java,generics,declaration,Java,Generics,Declaration,我正在阅读Gilad Bracha的《Java编程语言中的泛型》,我对声明的风格感到困惑。第8页有以下代码: interface Collection<E> { public boolean containsAll(Collection<?> c); public boolean addAll(Collection<? extends E> c); } interface Collection<E> { p
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!
}
接口集合
{
公共图书馆(c组);
公共布尔addAll(集合
该方法已具有与其关联的类型(布尔值)
这就是返回类型。该方法的完整类型是“采用集合
(对于某些T
)参数并返回布尔值
”的方法
这就是T
的作用:函数的参数使用它。换句话说,可以使用不同的类型作为参数调用此方法。这些类型的唯一限制是它们必须实现集合
接口,该接口本身依赖于泛型参数T
(存储在集合中的对象的类型)。尝试在不使用
的情况下编译它
基本上,它告诉编译器此方法包含泛型。在第一个示例中不需要它,因为?是一个特例,而第二个方法引用接口本身中定义的类型
另一方面,接口中不需要public。默认情况下,接口中的方法是public的,因此可以节省一些输入。它声明了该方法使用的泛型类型T
。而泛型类型E
对于整个接口是相同的T
仅限于声明的方法 此处使用的
(在方法声明中,返回类型之前)是泛型类型声明。您可以定义新的泛型类型以在方法中使用:据我所知,在这种情况下,
根本没有提供任何有用的内容。它创建的方法在功能上完全等同于使用通配符的方法
这里有几个例子,它将非常有用:
public List<?> transform(List<?> in);
//vs
public <T> List<T> transform(List<T> in);
公共列表转换(列表中);
//vs
公共列表转换(列表中);
在上面的示例中,您可以将返回类型与输入类型关联起来。第一个示例无法将两个通配符的运行时类型关联起来
public void add(List<?> list, Object obj);
//vs
public <T> void add(List<? super T> list, T obj);
公共作废添加(列表,对象obj);
//vs
public void add(ListThe?只是一个通配符。这意味着该方法将接受任何类型的集合
是方法的类型参数。它本质上是为通配符分配一个名称,然后可以在方法声明和定义的其他地方引用该名称
如果方法的返回类型根据传入的类型而变化,则可以更好地说明这种差异
假设你开始的方法是
对象getRandomElement(集合c)
这将接受任何集合,但无法约束其返回类型。因此,调用方必须将结果强制转换回它期望的任何类型——这应该可以工作,但会引发不安全的类型转换警告
使用类型参数,您将改为编写
T getRandomElement(集合c)
在这种情况下,如果您使用集合调用此方法
,编译器知道它将返回字符串
,如果您理解PEC,那么您将理解这些。请查看Oracle/Sun JDK 6中的此处,使用了第一个示例,因此我不知道您是否会使用第二个。为什么它比公共bo更好olean containsAll(集合c);
?但为什么这比看似功能等价的公共布尔containsAll(集合c)
?同样,为什么不公共布尔addAll(收集更好,因为方法的主体或定义可以引用类型T,代码可以避免强制转换,并由编译器保证类型安全。有关进一步的解释,请参阅我的答案。@Dave Costa:我没有看到您的答案,但使用
是否有助于其他方法无关紧要。我们现在讨论的是我自己thods,它似乎没有提供任何好处。@Mark——刚刚完成了我的回答。是的,你是对的,它在这些方法声明中没有任何区别——尽管t参数可能在实现体中被引用。但我认为原始问题更一般。说得好。我认为这是一个好问题经验法则是,只有当您具有参数化的返回类型(如Collections.emptyList()
)或需要将返回类型或其他参数与参数化或泛型参数关联时,才需要type参数。
public boolean containsAll(Collection<T> c);
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);