Collections.emptyList() возвращает Список<Object>?
-
08-07-2019 - |
Вопрос
У меня возникли некоторые проблемы с навигацией по правилу Java для вывода параметров универсального типа.Рассмотрим следующий класс, который имеет необязательный параметр list:
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()
?
Решение
Проблема, с которой вы сталкиваетесь, заключается в том, что даже несмотря на то, что метод 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()
вызов корректно вернул бы List<String>
.
Другие советы
Вы хотите использовать:
Collections.<String>emptyList();
Если вы посмотрите на исходный код what 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
.