Collections.emptyList() возвращает List <Object>?
У меня возникли проблемы с навигацией по правилу 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;
}
}
Мой компилятор Java дает следующую ошибку:
Person.java:9: The constructor Person(String, List<Object>) is undefined
Но Collections.emptyList()
возвращает тип <T> List<T>
, а не List<Object>
. Добавление роли не помогает
public Person(String name) {
this(name,(List<String>)Collections.emptyList());
}
дает
Person.java:9: inconvertible types
Используя EMPTY_LIST
вместо emptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
дает
Person.java:9: warning: [unchecked] unchecked conversion
В то время как следующее изменение приводит к ошибке:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
Может ли кто-нибудь объяснить, какое правило проверки типов я использую здесь, и лучший способ обойти его? В этом примере конечный пример кода является удовлетворительным, но с более крупными классами я бы хотел писать методы, следуя этому шаблону "необязательный параметр" без дублирования кода.
Для дополнительного кредита: когда целесообразно использовать EMPTY_LIST
, а не emptyList()
?
Ответы
Ответ 1
Проблема, с которой вы сталкиваетесь, заключается в том, что даже если метод emptyList()
возвращает List<T>
, вы не указали его с типом, поэтому он по умолчанию возвращает List<Object>
. Вы можете указать параметр типа, и ваш код будет вести себя так, как ожидалось, например:
public Person(String name) {
this(name,Collections.<String>emptyList());
}
Теперь, когда вы выполняете прямое задание, компилятор может определить параметры общего типа для вас. Он называл вывод типа. Например, если вы это сделали:
public Person(String name) {
List<String> emptyList = Collections.emptyList();
this(name, emptyList);
}
то вызов emptyList()
правильно вернет List<String>
.
Ответ 2
Вы хотите использовать:
Collections.<String>emptyList();
Если вы посмотрите на источник, для которого emptyList вы видите, что на самом деле это просто
return (List<T>)EMPTY_LIST;
Ответ 3
метод emptyList имеет такую подпись:
public static final <T> List<T> emptyList()
То, что <T>
перед словом List означает, что оно передает значение общего параметра T из типа переменной, которой назначен результат. Итак, в этом случае:
List<String> stringList = Collections.emptyList();
Возвращаемое значение затем явно ссылается на переменную типа List<String>
, поэтому компилятор может понять это. В этом случае:
setList(Collections.emptyList());
Нет никакой явной возвращаемой переменной для компилятора, чтобы использовать этот тип, поэтому по умолчанию он равен Object
.