通用方法调用

时间:2013-10-31 20:34:41

标签: java generics method-invocation

如果我们有通用方法

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

我们可以在调用此方法时显式定义type-parameter T

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

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

3 个答案:

答案 0 :(得分:5)

rules of method invocation are described in the Java Language Specification。在这种情况下,我们感兴趣

  

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

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

<?>是狂野类型,<List<?>>不是。

至于原因,请考虑

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

你甚至可以在<?>中使用listFactory()做什么? ?未知。你将无法做到

new ArrayList<?>(); 

因为JLS prohibits it

  

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

但是你也不能把它用在其他任何东西上。

答案 1 :(得分:1)

  

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

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

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

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

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

这就是为什么:

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

来自Java Generics and Collections

  

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

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设计师每个人都记得   通配符类型是一些普通类型的简写,所以他们认为最终每一个   对象应该使用普通类型创建。目前尚不清楚这种限制是否存在   必要的,但不太可能是一个问题。

答案 2 :(得分:0)

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

class CompletelyUnrelatedBogusClass { }

SClass.< CompletelyUnrelatedBogusClass >listFactory();

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