Java泛型:方法声明参数中的类型扩展

7

我在学习Java泛型。我的理解是,泛型通过类型来参数化集合。在Oracle的教程中有以下评论:

在泛型代码中,问号(?)称为通配符,表示未知类型。

下一页中有一个带有上限通配符的方法声明示例:

public void process(List<? extends Foo> list)

鉴于此,我想知道为什么这个方法声明是非法的:
public void process(List<E extends Number> list)

而这个是合法的:

public <E extends Number> void process(List<E> list)
4个回答

6

在指定方法参数类型时,您正在使用通用类型,因此必须事先定义。在此语句中,您使用未定义的E。

public void process(List<E extends Number> list) { /* ... */ }

然而,在第二个例子中,它在方法返回类型 (void) 之前被定义:
public <E extends Number> void process(List<E> list) { /* ... */ }

我认为这实际上是问题的重新陈述。那么,为什么允许使用通配符参数而不需要“前期定义”?既然允许这样做,为什么对“T”会施加这样的限制呢? - Schemer
2
但是通配符是在JVM中定义的。它是一种特殊情况,内置于语言中。另一方面,T是您想出来的东西,因此在使用之前必须告诉Java T是什么。它可以是简单的<T>或更受限制的<T extends Number>,但在使用之前必须定义。 - Ali Cheaito
非常感谢,phoenix。我一直认为“T”和“?”只是泛型中的标记。在谷歌搜索通配符时,大多数帖子都是关于肯定这个概念的泛型。刚才我在谷歌上搜索了“java通配符-generics”,发现了java.lang.reflect接口WildcardType。文档说:“WildcardType表示通配符类型表达式,例如?、?extends Number或?super Integer。”这对我来说不太清楚。问号是某种内置对象吗?实现了这个接口?我的Java功夫非常生疏。 :-) - Schemer

4

没有比“因为语言设计就是这样”更好的答案了。但是,可以这样思考:类型参数就像方法的另一个参数列表一样处理:它们必须全部在一个(有序的)列表中同时出现。

您可以通过显式传递类型参数来调用泛型方法。例如:foo.<Integer, String>process(list)。这意味着类型参数必须具有明确的顺序,就像普通值参数一样。


3
为了补充@phoenix的答案,这个声明中存在的问题是:
public void process(List<E extends Number> list) { /* ... */ }

这意味着你的泛型类型E的声明位置不正确。正确的位置是在返回类型之前:

public <E extends Number> void process(List<E> list) { /* ... */ }

然而,定义泛型类型的另一个可能的位置是在类声明本身中:

class MyClass<E extends Number> {

    public void process(List<E> list) { /* ... */ }

}

0

大致上两者是相同的,但我只使用第一个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接