Универсальный сбивает с толку несвязанную коллекцию
Почему коллекции, не связанные с классом шаблона, теряют свой тип? Вот пример: (Извините, он не скомпилируется из-за ошибки, из-за которой я запутался.)
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++, - это синтаксис <>:)
Подробнее: что такое необработанный тип и почему мы не должны его использовать?
Это действительно похоже на эту ошибку:
6760983: ошибка запуска неиспользуемого параметра типа в несвязанном методе
Который сообщается здесь:
Во-первых, в 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
родовой.