Универсальный сбивает с толку несвязанную коллекцию

Почему коллекции, не связанные с классом шаблона, теряют свой тип? Вот пример: (Извините, он не скомпилируется из-за ошибки, из-за которой я запутался.)

package test;

import java.util.ArrayList;
import java.util.List;

public class TemplateTest {

    public static class A { }

    public static class B<T extends Comparable> {
        List<A> aList = new ArrayList<A>();

        public List<A> getAList() {
            return aList;
        }

        public int compare(T t, T t1) {
            return t.compareTo(t1);
        }
    }

    public static void main(String[] args) {
        B b = new B();
        for (A a : b.getAList()) { //THIS DOES NOT WORK

        }
        List<A> aList = b.getAList(); //THIS WORKS
        for (A a : aList) {

        }
    }
}

Этот код выдает ошибку при компиляции:

test/TemplateTest.java:24: incompatible types
    found   : java.lang.Object
    required: test.TemplateTest.A
        for (A a : b.getAList()) {

Если я укажу шаблон B лайк B<String>или если я полностью удалю шаблон из B, то все в порядке.

В чем дело?

РЕДАКТИРОВАТЬ: люди указали, что нет необходимости делать B общего, поэтому я добавил в B

3 ответа

Решение

Да, известно поведение, что если вы используете необработанный тип, то все параметры типа в классе будут потеряны, а не только параметр уровня типа, который вы не смогли объявить.

Проблема частично здесь:

Если я укажу шаблон B, как B<String>или если я полностью удалю шаблон из B, то все в порядке.

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

List<A> list = b.getList() не может успешно интерпретировать тип, он просто эффективно придерживается произвольного приведения и доверяет вам, что назначение является правильным. Если вы посмотрите на предупреждения компилятора, он фактически генерирует предупреждение для небезопасного преобразования.

for(A a : b.getList()) {} обновляет это предупреждение до ошибки, потому что вставленное приведение будет внутри кода, сгенерированного компилятором, поэтому он вообще отказывается автоматически генерировать небезопасный код, а не просто выдает предупреждение.

Из спецификации языка Java:

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

Суть в том, что единственная важная вещь, которую дженерики Java делят с шаблонами C++, - это синтаксис <>:)

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

Во-первых, в Java это Generics, а не шаблоны, как в C++.

Вы объявляете параметр общего типа T в вашем классе B но ты не используешь это. Вы должны использовать T вместо A на протяжении всего вашего B определение класса.

public static class B<T> {
    List<T> aList = new ArrayList<T>();

    public List<T> getAList() {
        return aList;
    }
}

Тогда вы должны использовать параметр типа при объявлении вашего экземпляра класса B,

B<A> b = new B<A>();

Но если вы знаете, что ваш aList переменная всегда будет содержать объекты типа A как имя метода getAList предполагает, что не было бы причин делать уроки B родовой.

Другие вопросы по тегам