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

Почему алмаз не может выводить типы на анонимные внутренние классы?

Возможный дубликат:
Инициализация двойной скобки (анонимный внутренний класс) с алмазным оператором

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

List<String> list = new ArrayList<>();

Однако он не может для анонимных внутренних классов следующим образом:

List<String> st = new List<>() { //Doesn't compile

    //Implementation here

}

Почему это? Логически в этом сценарии я могу определенно указать тип как String. Есть ли логическая причина для этого решения, когда тип не может быть фактически выведен на анонимные внутренние классы, или он был опущен по другим причинам?

4b9b3361

Ответ 1

В JSR-334:

Использование алмаза с анонимными внутренними классами не поддерживается, поскольку для этого в общем случае потребуется расширение файла класса атрибут подписи для представления недентифицируемых типов, де-факто JVM изменение.

Я думаю, что, как известно, анонимный класс приводит к поколению собственного файла класса.

Я предполагаю, что общий тип не существует в этих файлах и скорее заменен эффективным (статическим) типом (таким образом, объявленным явным типом, таким как <String> в момент времени объявления).

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

Было бы более трудно достижимым (и, безусловно, бесполезным) для компилятора принудительное расширение (путем добавления специального атрибута для generics) к тезисов типа файлов классов.

Ответ 2

google yields, после пропуска сообщений из stackoverflow, http://mail.openjdk.java.net/pipermail/coin-dev/2011-June/003283.html

Я предполагаю, что это так, обычно анонимный класс представляет собой конкретный подкласс кажущегося типа

    interface Foo<N extends Number>
    {
        void foo(N n);
    }

    Foo<Integer> foo = new Foo<Integer>(){ ... }

реализуется

    class AnonFoo_1 implements Foo<Integer>{ ... }

    Foo<Integer> foo = new AnonFoo_1();

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

    Foo<? extends Runnable> foo = new Foo<>(){ ... }

Правила вывода дают N=Number&Runnable; после трюка, который нам нужен, нам нужно

    class AnonFoo_2 implements Foo<Number&Runnable>{ ... }

В настоящее время это запрещено; тип arg to super type Foo должен быть "нормальным" типом.


Однако обоснование не очень сильное. Мы можем придумать другие приемы реализации, чтобы заставить его работать.

    class AnonFoo<N extends Number&Runnable> implements Foo<N>
    {
        @Override public void foo(N n)
        {
            n.intValue();
            n.run();
        }
    }

    Foo<? extends Runnable> foo = new AnonFoo<>();

компилятор должен иметь возможность сделать тот же трюк.

В любом случае, по крайней мере, компилятор должен разрешить большинство случаев использования, которые не включают "неопровержимые типы", например Foo<Integer> foo = new Foo<>(){...} Жаль, что эти обычные/простые случаи также излишне запрещены.

Ответ 3

Короче говоря, <> мало что делает для вывода типов, он отключает предупреждение, которое вы получите без него.

EDIT: как указывает @Natix, он выполняет некоторую проверку.

List<Integer> ints = new ArrayList<>();
List<String> copy = new ArrayList<>(ints);

создает ошибку компиляции

Error:Error:line (42)error: incompatible types
required: List<String>
found:    ArrayList<Integer>

Как вы видите, <> принимает тип аргумента, не вызывая тип из типа copy