Подтвердить что ты не робот

Общий вывод в конструкторах

Если у меня есть класс Foo:

public class Foo<T> {
    public Foo(T t) {
        //do something
    }

    public static <E> void bar(E e) {
         //do something
    }
}

Почему Foo.bar("String"); делает вывод, что E является строкой (и поэтому не выдает предупреждение компилятора), но new Foo("String"); не означает, что T является строкой?

4b9b3361

Ответ 1

Поскольку конструктор можно рассматривать как специальный метод экземпляра, он не набирается - он получает свой тип от имени класса (с параметром типа), например Foo<String>. т.е. конструктор не определяется как:

public <T> Foo(T t) ...

и не может быть. Это позволит скрыть общий тип класса (и вы получите предупреждение)

Набирается статический метод. FYI, вызов с несимметричным параметром, как только будет выведен тип, эквивалентен:

Foo.<String>bar("String");

Ответ 2

Когда Java реализовал generics, было решено, что генерируемый класс, созданный без параметров типа, всегда будет возвращать raw-type. Это отличается от общих методов отсутствующими параметрами типа, которые компилятор пытается вывести тип. Из учебников по Java:

Как правило, компилятор Java может вывести параметры типа общего вызова метода. Следовательно, в большинстве случаев вам не нужно указывать их.

Но когда обсуждение переходит к конструкторам:

Обратите внимание, что для использования автоматического вывода типа во время создания экземпляра универсального класса вы должны указать алмаз. В следующем примере компилятор генерирует предупреждение без предупреждения, потому что конструктор HashMap() ссылается на тип HashMap raw, а не тип Map<String, List<String>>:

Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning

источник: http://download.oracle.com/javase/tutorial/java/generics/gentypeinference.html

Это остается тем же самым в Java 7, однако они пытались сделать его менее повторяющимся, поддерживая синтаксис бриллианта. Например, Foo<String> foo = new Foo<>("String"). См. этот раздел той же статьи.

Ответ 3

Думаю, вам нужно это сделать

new Foo<String>("String");

сообщить, передают ли данные генериков; аналогично API коллекций.

Ответ 4

Взглянув в это, я собираюсь угадать здесь. Рассмотрим следующее:

public class Foo {
    public <E> Foo(E t) {
        //do something
    }

    public static <E> void bar(E e) {
         //do something
    }
}

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

Foo f = new Foo("String");

Это работает, потому что здесь вызывается тип E. Так же, как вы ожидаете, что это произойдет в случае метода. Однако ошибка, которую вы получаете, связана не с тем, что тип аргумента не выводится, а потому, что тип raw для класса не может быть выведен.

Я думаю, что это сводится к тому, что тип raw класса может распространяться на методы, но методы не могут установить класс raw типа с использованием вывода.

Ответ 5

Ответ

@Kublai Khan правильный; тип new Foo(s) является raw Foo, для обратной совместимости.

Вывод типа XML-конструктора Java7 (new Foo<>(s)) совпадает с термином метода метода методом method.

http://cr.openjdk.java.net/~darcy/ProjectCoin/ProjectCoin-Documentation-v0.9375.html#diamond

Если выражение создания экземпляра класса использует "< > " для исключения аргументов типа класса, список методов m1... mk определяется с целью разрешения перегрузки и вывода аргумента типа...

... затем выбирается один из m1... mk, используя процесс, описанный в п. 15.12.2 (Определение сигнатуры метода)

Ваше подозрение верно, конструкторы могут использовать вывод так же, как и методы, нет существенных различий. Вам просто нужно добавить <> из-за проблемы с обратной совместимостью.

Почему это потребовало Java 6 лет, чтобы добавить эту функцию - это еще одна история.