2

如果我们有泛型方法

class SClass{
    public static <T> ArrayList<T> listFactory(){ return new ArrayList<T>(); }
}

我们可以T在调用此方法时显式定义类型参数。

SClass.<?>listFactory();//compile error
SClass.<List<?>>listFactory();//ok

为什么我们不能listFactory使用类型参数调用?,但可以使用List<?>

4

3 回答 3

5

Java 语言规范中描述了方法调用的规则。在这种情况下,我们感兴趣

方法调用表达式用于调用类或实例方法。

[...]
TypeName . NonWildTypeArguments Identifier ( ArgumentListopt )

<?>是野生型,<List<?>>不是。

至于原因,请考虑

SClass.<?>listFactory();//compile error

你甚至可以用<?>in做listFactory()什么??是未知的。你做不到

new ArrayList<?>(); 

因为JLS 禁止它

如果类实例创建表达式中使用的任何类型参数是通配符类型参数(第 4.5.1 节),则会出现编译时错误。

但是你也不能将它与其他任何东西一起使用。

于 2013-10-31T20:47:09.313 回答
1

为什么我们不能使用类型参数调用 listFactory?,但可以使用 List?

实例创建在类实例创建表达式中,如果类型是参数化类型,则所有类型参数都不能是通配符。我认为它是一样的:

List<?> list = new ArrayList<?>(); // compile-time error

只有实例创建中的顶级参数才禁止包含通配符。允许使用嵌套通配符。因此,以下内容是合法的:

List<List<?>> lists = new ArrayList<List<?>>(); // ok

这是一个原因:

SClass.<List<?>>listFactory();//ok

来自 Java 泛型和集合

泛型方法调用如果泛型方法调用包括显式类型参数,则这些类型参数不能是通配符。

class SClass{
    public static <T> ArrayList<T> listFactory(){ return new ArrayList<T>(); }
}

您可以选择要推断的类型参数,也可以传递显式类型参数。以下两种都是合法的:

List<?> list = Lists.factory();
List<?> list = Lists.<Object>factory();

如果传递了显式类型参数,则它不能是通配符:

List<?> list = Lists.<?>factory(); // compile-time error

允许嵌套通配符:

List<List<?>> = Lists.<List<?>>factory(); // ok

Java 设计者考虑到每个通配符类型都是一些普通类型的简写,因此他们认为最终每个对象都应该使用普通类型创建。目前尚不清楚这种限制是否有必要,但不太可能成为问题。

于 2013-10-31T20:44:21.760 回答
0

而不是SClass.<?>listFactory()你可以使用:

class CompletelyUnrelatedBogusClass { }

SClass.< CompletelyUnrelatedBogusClass >listFactory();

由于?是未知的,这意味着它不对它是什么做任何假设。这意味着您可以将任何引用类型放在那里,这将是正确的。

于 2013-11-01T23:38:01.430 回答