Расширенный полиморфизм в Java
У меня есть классы в продвинутом программировании в моем университете, и у меня есть небольшая проблема с пониманием того, как работает этот код.
public final class GenericClass<T> {
private void overloadedMethod(Collection<?> o) {
System.out.println("Collection<?>");
}
private void overloadedMethod(List<Number> o) {
System.out.println("List<Number>");
}
private void overloadedMethod(ArrayList<Integer> o) {
System.out.println("ArrayList<Integer>");
}
public void method(List<T> l) {
overloadedMethod(l);
}
public static void main(String[] args) {
GenericClass<Integer> test = new GenericClass<Integer>();
test.method(new ArrayList<Integer>());
}
}
Почему этот код печатает "Collection <?"??
Ответы
Ответ 1
Объявление method(List<T> l)
не указывает никаких границ типа T. Нет гарантии, что T является Number или подклассом Number. Поэтому компилятор может решить, что этот метод вызывает overloadedMethod(Collection<?> o)
.
Помните: после компиляции информация о generics больше не доступна в файлах классов.
Ответ 2
Всякий раз, когда вы определяете общий тип, автоматически предоставляется соответствующий тип raw
Этот метод
public void method(List<T> l) {
}
заменяется на
public void method(List<Object> l) {
}
Если вы читаете о типах подстановочных знаков, вы увидите, что List<Number>
и List<Object>
или ArrayList<Integer>
и List<Object>
не имеет отношения типа. List<Object>
является подтипом Collecion<?>
, поэтому этот метод вызывается.
Ответ 3
когда вы имеете дело с перегрузкой метода, вы должны вставить три понятия в свой ум:
ваша проблема лежит в первой точке, которая расширяется, java-компилятор дает приоритеты каждой из этих концепций в том же порядке, что и они перечислены выше, поэтому он предпочитает расширение и когда вы вызываете ваш метод как test.method(new ArrayList<Integer>());
, компилятор находит что ArrayList<Integer>()
можно расширить до Collection<?>
, и поскольку он имеет наивысший приоритет, он вызывает эту версию и пренебрегает другими
Примечание: если вы измените объявление двух других методов на private void overloadedMethod(ArrayList<?> o)
и private void overloadedMethod(List<?> o)
, компилятор также выведет версию Collection<?>
, потому что это предпочтительный