Вопрос

У меня возникли некоторые проблемы с навигацией по правилу 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top