Есть вот такой java класс:
public class SomeType<T> {
public <E> void test(Collection<E> collection) {
for (E e : collection) {
System.out.println(e);
}
}
public void test(List<Integer> list) {
for (Integer integer : list) {
System.out.println(integer);
}
}
}
Если исполнять код так (создать класс любым из трех вариантов):
public static void main(String[] args) {
SomeType someType = new SomeType<>();
//SomeType someType = new SomeType<String>();
//SomeType someType = new SomeType();
List<String> stringList = Arrays.asList("value");
someType.test(stringList);
}
то выбрасывается:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
И только при таком выполнении
public static void main(String[] args) {
SomeType<String> someType = new SomeType<>();
List<String> stringList = Arrays.asList("value");
someType.test(stringList);
}
код отрабатывает успешно и на экран выводится value.
Может кто-нибудь объяснить почему именно так работает java? Вроде бы дженерик тип класса T не связан с дженерик типом метода E.
И еще, если класс не дженерик:
public class SomeType {
public <E> void test(Collection<E> collection) {
for (E e : collection) {
System.out.println(e);
}
}
public void test(List<Integer> list) {
for (Integer integer : list) {
System.out.println(integer);
}
}
}
то такой код отрабатывает нормально
public static void main(String[] args) {
SomeType someType = new SomeType();
List<String> stringList = Arrays.asList("value");
someType.test(stringList);
}
в первом варианте, вы создает экземпляр SomeType сырого типа, параметризованные методы экземпляра сырого типа затираются и ваш метод с дженериком Е, после компиляции, превращается в метод вида :
public Object void test(Collection collection) {
for (Object e : collection) {
System.out.println(e);
}
}
при вызове на вход метода подается List<String>, так как обобщенные типы инвариантны, параметр List<String> инвариант для Collection, не расширяет его, поэтому компилятор не связывает вызов с первым, дженерализированным(до компиляции) методом.
А вот второй метод, превращается в следующее:
public void test(List list) {
for (Integer integer : list) {
System.out.println(integer);
}
}
и может принять на вход лист чего угодно, получает List<String> и пытается прикастовать элемент к Integer.
Для того чтобы ваш код в первом случае правильно работал вы может подать на вход такую конструкцию Collection stringList = Arrays.asList("value");
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости