I'm having some trouble navigating Java's rule for inferring generic type parameters. Consider the following class, which has an optional list parameter:
我在使用Java规则来推断泛型类型参数时遇到了一些麻烦。考虑下面的类,它有一个可选的列表参数:
import java.util.Collections;
import java.util.List;
public class Person {
private String name;
private List<String> nicknames;
public Person(String name) {
this(name,Collections.emptyList());
}
public Person(String name,List<String> nicknames) {
this.name = name;
this.nicknames = nicknames;
}
}
My Java compiler gives the following error:
我的Java编译器给出如下错误:
Person.java:9: The constructor Person(String, List<Object>) is undefined
But Collections.emptyList()
returns type <T> List<T>
, not List<Object>
. Adding a cast doesn't help
但是Collections.emptyList()返回类型
public Person(String name) {
this(name,(List<String>)Collections.emptyList());
}
yields
收益率
Person.java:9: inconvertible types
Using EMPTY_LIST
instead of emptyList()
使用EMPTY_LIST而不是emptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
yields
收益率
Person.java:9: warning: [unchecked] unchecked conversion
Whereas the following change makes the error go away:
而下面的更改使错误消失:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
Can anyone explain what type-checking rule I'm running up against here, and the best way to work around it? In this example, the final code example is satisfactory, but with larger classes, I'd like to be able to write methods following this "optional parameter" pattern without duplicating code.
谁能解释一下我在这里遇到的类型检查规则,以及解决它的最佳方法吗?在这个示例中,最终的代码示例是令人满意的,但是对于更大的类,我希望能够按照这个“可选参数”模式编写方法,而无需重复代码。
For extra credit: when is it appropriate to use EMPTY_LIST
as opposed to emptyList()
?
对于额外的学分:什么时候使用EMPTY_LIST而不是emptyList()合适?
3 个解决方案
#1
399
The issue you're encountering is that even though the method emptyList()
returns List<T>
, you haven't provided it with the type, so it defaults to returning List<Object>
. You can supply the type parameter, and have your code behave as expected, like this:
您遇到的问题是,尽管方法emptyList()返回列表
public Person(String name) {
this(name,Collections.<String>emptyList());
}
Now when you're doing straight assignment, the compiler can figure out the generic type parameters for you. It's called type inference. For example, if you did this:
当你做直接赋值时,编译器可以帮你算出泛型类型参数。它被称为类型推断。例如,如果你这样做:
public Person(String name) {
List<String> emptyList = Collections.emptyList();
this(name, emptyList);
}
then the emptyList()
call would correctly return a List<String>
.
然后emptyList()调用将正确地返回一个列表
#2
87
You want to use:
你想使用:
Collections.<String>emptyList();
If you look at the source for what emptyList does you see that it actually just does a
如果你看一下emptyList的源代码你会发现它实际上只做了a
return (List<T>)EMPTY_LIST;
#3
26
the emptyList method has this signature:
emptyList方法有以下签名:
public static final <T> List<T> emptyList()
That <T>
before the word List means that it infers the value of the generic parameter T from the type of variable the result is assigned to. So in this case:
单词列表前的
List<String> stringList = Collections.emptyList();
The return value is then referenced explicitly by a variable of type List<String>
, so the compiler can figure it out. In this case:
然后,返回值由类型列表
setList(Collections.emptyList());
There's no explicit return variable for the compiler to use to figure out the generic type, so it defaults to Object
.
编译器没有明确的返回变量来计算泛型类型,所以它默认为Object。
#1
399
The issue you're encountering is that even though the method emptyList()
returns List<T>
, you haven't provided it with the type, so it defaults to returning List<Object>
. You can supply the type parameter, and have your code behave as expected, like this:
您遇到的问题是,尽管方法emptyList()返回列表
public Person(String name) {
this(name,Collections.<String>emptyList());
}
Now when you're doing straight assignment, the compiler can figure out the generic type parameters for you. It's called type inference. For example, if you did this:
当你做直接赋值时,编译器可以帮你算出泛型类型参数。它被称为类型推断。例如,如果你这样做:
public Person(String name) {
List<String> emptyList = Collections.emptyList();
this(name, emptyList);
}
then the emptyList()
call would correctly return a List<String>
.
然后emptyList()调用将正确地返回一个列表
#2
87
You want to use:
你想使用:
Collections.<String>emptyList();
If you look at the source for what emptyList does you see that it actually just does a
如果你看一下emptyList的源代码你会发现它实际上只做了a
return (List<T>)EMPTY_LIST;
#3
26
the emptyList method has this signature:
emptyList方法有以下签名:
public static final <T> List<T> emptyList()
That <T>
before the word List means that it infers the value of the generic parameter T from the type of variable the result is assigned to. So in this case:
单词列表前的
List<String> stringList = Collections.emptyList();
The return value is then referenced explicitly by a variable of type List<String>
, so the compiler can figure it out. In this case:
然后,返回值由类型列表
setList(Collections.emptyList());
There's no explicit return variable for the compiler to use to figure out the generic type, so it defaults to Object
.
编译器没有明确的返回变量来计算泛型类型,所以它默认为Object。