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.