Почему делает использование, Collections.emptySet () с дженериками работают в присвоении, но не как параметр метода?

Так, у меня есть класс с конструктором как это:

public FilterList(Set<Integer> labels) {
    ...
}

и я хочу создать новое FilterList объект с пустым множеством. Следуя совету Joshua Bloch в его книге Эффективный Java, я не хочу создавать новый объект для пустого множества; я буду просто использовать Collections.emptySet() вместо этого:

FilterList emptyList = new FilterList(Collections.emptySet());

Это дает мне ошибку, жалуясь это java.util.Set<java.lang.Object> не a java.util.Set<java.lang.Integer>. Хорошо, как насчет этого:

FilterList emptyList = new FilterList((Set<Integer>)Collections.emptySet());

Это также дает мне ошибку! Хорошо, как насчет этого:

Set<Integer> empty = Collections.emptySet();
FilterList emptyList = new FilterList(empty);

Эй, это работает! Но почему? В конце концов, Java не имеет вывода типа, который является, почему Вы получаете преобразование непроверенное, предупреждающее, если Вы делаете Set<Integer> foo = new TreeSet() вместо Set<Integer> foo = new TreeSet<Integer>(). Но Set<Integer> empty = Collections.emptySet(); работы даже без предупреждения. Почему это?

54
задан Mechanical snail 14 January 2013 в 19:20
поделиться

4 ответа

Короткий ответ - это ограничение вывода типа в общей системе Java. Он может выводить универсальные типы по конкретным переменным, но не по параметрам метода.

Я подозреваю , что это связано с тем, что методы отправляются динамически в зависимости от класса времени выполнения объекта-владельца, поэтому во время компиляции (когда вся общая информация разрешена) вы не можете на самом деле точно знать, каким будет класс параметра метода, и, следовательно, не может сделать вывод. Объявления переменных красивы и постоянны, так что вы можете.

Кто-то другой может дать более подробную информацию и / или красивую ссылку. : -)

В любом случае, вы всегда можете явно указать параметры типа для общих вызовов, например так:

Collections.<Integer>emptySet();

или даже несколько параметров одновременно, например

Collections.<String, Boolean>emptyMap(); // Returns a Map<String, Boolean>

Это часто выглядит немного чище, чем приведение, в случаях, когда логический вывод не срабатывает.

118
ответ дан 7 November 2019 в 07:47
поделиться

В Java есть вывод типа, но он довольно ограничен. Если вам интересно узнать, как именно это работает и каковы его ограничения, это действительно хорошее чтение:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Type%2BArgument%2BInference

5
ответ дан 7 November 2019 в 07:47
поделиться

try

FilterList emptyList = new FilterList(Collections.<Integer>emptySet());

Вы можете принудительно указать параметр типа для методов, у которых они есть, в случаях, когда вывод недостаточно хорош, или чтобы позволить вам использовать подтипы; например:

// forces use of ArrayList as parameter instead of the infered List
List<String> l = someObject.<ArrayList<String> methodThatTakesTypeParamForReturnType();
7
ответ дан 7 November 2019 в 07:47
поделиться

Вы хотите сделать следующее:

FilterList emptyList = new FilterList(java.util.Collections.<Integer>emptySet());

Это сообщает методу emptySet , что его общий параметр должен быть явно Integer вместо значения по умолчанию ] Объект . И да, синтаксис для этого совершенно забавный и не интуитивно понятный. :)

6
ответ дан 7 November 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: