Коллекции.emptyList() возвращает список?
у меня возникли некоторые проблемы с навигацией по правилу 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()
?
3 ответа:
проблема возникает в том, что даже если метод
emptyList()
возвращаетList<T>
, вы не предоставили ему тип, поэтому по умолчанию он возвращаетList<Object>
. Вы можете указать параметр type, и ваш код будет вести себя так, как ожидалось, например:public Person(String name) { this(name,Collections.<String>emptyList()); }
теперь, когда вы делаете прямое назначение, компилятор может выяснить параметров универсального типа для вас. Это называется вывод типа. Например, если вы сделали это:
public Person(String name) { List<String> emptyList = Collections.emptyList(); this(name, emptyList); }
затем
emptyList()
вызов будет правильно возвращать aList<String>
.
вы хотите использовать:
Collections.<String>emptyList();
Если вы посмотрите на источник для того, что emptyList вы видите, что он на самом деле просто делает
return (List<T>)EMPTY_LIST;
метод emptyList имеет такую подпись:
public static final <T> List<T> emptyList()
это
<T>
перед списком слов означает, что он выводит значение универсального параметра T из типа переменной, которой назначен результат. Так что в данном случае:List<String> stringList = Collections.emptyList();
возвращаемое значение затем явно ссылается на переменную типа
List<String>
, так что компилятор может выяснить это. В этом случае:setList(Collections.emptyList());
нет явной возвращаемой переменной для компилятора, чтобы выяснить универсальный тип, поэтому по умолчанию он
Object
.