Коллекции.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 240

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() вызов будет правильно возвращать a List<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.