为什么我不能将类型参数显式传递给通用Java方法?

时间:2021-09-04 01:10:57

I have defined a Java function:

我已经定义了一个Java函数:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

One way to call it is like so:

调用它的一种方法是这样的:

List<Integer> myList = createEmptyList(); // Compiles

Why can't I call it by explicitly passing the generic type argument? :

为什么我不能通过显式传递泛型类型参数来调用它? :

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

I get the error Illegal start of expression from the compiler.

我从编译器得到错误Illegal start of expression。

4 个解决方案

#1


32  

When the java compiler cannot infer the parameter type by itself for a static method, you can always pass it using the full qualified method name: Class . < Type > method();

当java编译器无法为静态方法自己推断参数类型时,您始终可以使用完全限定的方法名称传递它:Class。 方法();

Object list = Collections.<String> emptyList();

#2


22  

You can, if you pass in the type as a method parameter.

如果将类型作为方法参数传入,则可以。

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Methods cannot be genericised in the same way that a type can, so the only option for a method with a dynamically-typed generic return type -- phew that's a mouthful :-) -- is to pass in the type as an argument.

方法不能以类型的方式进行泛化,因此具有动态类型泛型返回类型的方法的唯一选项 - phew是满口的:-) - 是将类型作为参数传递。

For a truly excellent FAQ on Java generics, see Angelika Langer's generics FAQ.

有关Java泛型的真正优秀常见问题解答,请参阅Angelika Langer的泛型常见问题解答。

.
.

Follow-up:

It wouldn't make sense in this context to use the array argument as in Collection.toArray( T[] ). The only reason an array is used there is because the same (pre-allocated) array is used to contain the results (if the array is large enough to fit them all in). This saves on allocating a new array at run-time all the time.

在此上下文中使用数组参数在Collection.toArray(T [])中是没有意义的。在那里使用数组的唯一原因是因为使用相同的(预分配的)数组来包含结果(如果数组足够大以使它们全部适合)。这节省了在运行时始终分配新阵列的过程。

However, for the purposes of education, if you did want to use the array typing, the syntax is very similar:

但是,出于教育目的,如果您确实想要使用数组类型,则语法非常相似:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

#3


1  

It was quite some time since I dug into those parts of Java, but...

自从我挖掘Java的那些部分以来已经有一段时间了,但......

Why you can't do it was probably a design choice by the language developers. Still, due to the type erasure employed by Java, the generics information gets dropped at compile time anyway, so in your example it would create exactly the same byte code whether you had the type parameter or not.

为什么你不能这样做可能是语言开发人员的设计选择。尽管如此,由于Java使用的类型擦除,泛型信息无论如何都会在编译时被删除,因此在您的示例中,无论您是否具有类型参数,它都将创建完全相同的字节代码。

#4


0  

@pauldoo Yes, you are quite right. It is one of the weaknesses with the java generics imho.

@pauldoo是的,你是对的。这是java泛型imho的弱点之一。

I response to Cheekysoft I'd like to propose to also look at how it is done by the Java people themselves, such as T[] AbstractCollection#toArray(T[] a). I think Cheekysofts version is superior, but the Java one has the advantage of familiarity.

我对Cheekysoft的回应我想建议看一下Java人员自己如何做,比如T [] AbstractCollection#toArray(T [] a)。我认为Cheekysofts版本更优越,但Java版本具有熟悉的优势。

Edit: Added link. Re-edit: Found a bug on SO :)

编辑:添加链接。重新编辑:在SO上发现了一个bug :)


Follow-up on Cheekysoft: Well, as it is a list of some type that should be returned the corresponding example should look something like:

关于Cheekysoft的后续行动:嗯,因为它是应该返回的某种类型的列表,相应的示例应该类似于:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

But yes, passing the class object is clearly the better one. My only argument is that of familiarity, and in this exact instance it isn't worth much (in fact it is bad).

但是,传递类对象显然是更好的。我唯一的论点是熟悉,而在这个确切的例子中它不值得(事实上它很糟糕)。

#1


32  

When the java compiler cannot infer the parameter type by itself for a static method, you can always pass it using the full qualified method name: Class . < Type > method();

当java编译器无法为静态方法自己推断参数类型时,您始终可以使用完全限定的方法名称传递它:Class。 方法();

Object list = Collections.<String> emptyList();

#2


22  

You can, if you pass in the type as a method parameter.

如果将类型作为方法参数传入,则可以。

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Methods cannot be genericised in the same way that a type can, so the only option for a method with a dynamically-typed generic return type -- phew that's a mouthful :-) -- is to pass in the type as an argument.

方法不能以类型的方式进行泛化,因此具有动态类型泛型返回类型的方法的唯一选项 - phew是满口的:-) - 是将类型作为参数传递。

For a truly excellent FAQ on Java generics, see Angelika Langer's generics FAQ.

有关Java泛型的真正优秀常见问题解答,请参阅Angelika Langer的泛型常见问题解答。

.
.

Follow-up:

It wouldn't make sense in this context to use the array argument as in Collection.toArray( T[] ). The only reason an array is used there is because the same (pre-allocated) array is used to contain the results (if the array is large enough to fit them all in). This saves on allocating a new array at run-time all the time.

在此上下文中使用数组参数在Collection.toArray(T [])中是没有意义的。在那里使用数组的唯一原因是因为使用相同的(预分配的)数组来包含结果(如果数组足够大以使它们全部适合)。这节省了在运行时始终分配新阵列的过程。

However, for the purposes of education, if you did want to use the array typing, the syntax is very similar:

但是,出于教育目的,如果您确实想要使用数组类型,则语法非常相似:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

#3


1  

It was quite some time since I dug into those parts of Java, but...

自从我挖掘Java的那些部分以来已经有一段时间了,但......

Why you can't do it was probably a design choice by the language developers. Still, due to the type erasure employed by Java, the generics information gets dropped at compile time anyway, so in your example it would create exactly the same byte code whether you had the type parameter or not.

为什么你不能这样做可能是语言开发人员的设计选择。尽管如此,由于Java使用的类型擦除,泛型信息无论如何都会在编译时被删除,因此在您的示例中,无论您是否具有类型参数,它都将创建完全相同的字节代码。

#4


0  

@pauldoo Yes, you are quite right. It is one of the weaknesses with the java generics imho.

@pauldoo是的,你是对的。这是java泛型imho的弱点之一。

I response to Cheekysoft I'd like to propose to also look at how it is done by the Java people themselves, such as T[] AbstractCollection#toArray(T[] a). I think Cheekysofts version is superior, but the Java one has the advantage of familiarity.

我对Cheekysoft的回应我想建议看一下Java人员自己如何做,比如T [] AbstractCollection#toArray(T [] a)。我认为Cheekysofts版本更优越,但Java版本具有熟悉的优势。

Edit: Added link. Re-edit: Found a bug on SO :)

编辑:添加链接。重新编辑:在SO上发现了一个bug :)


Follow-up on Cheekysoft: Well, as it is a list of some type that should be returned the corresponding example should look something like:

关于Cheekysoft的后续行动:嗯,因为它是应该返回的某种类型的列表,相应的示例应该类似于:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

But yes, passing the class object is clearly the better one. My only argument is that of familiarity, and in this exact instance it isn't worth much (in fact it is bad).

但是,传递类对象显然是更好的。我唯一的论点是熟悉,而在这个确切的例子中它不值得(事实上它很糟糕)。