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

Расширенный полиморфизм в 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 <?"??

4b9b3361

Ответ 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

когда вы имеете дело с перегрузкой метода, вы должны вставить три понятия в свой ум:

  • Расширяя
  • Бокс
  • Var_args

ваша проблема лежит в первой точке, которая расширяется, java-компилятор дает приоритеты каждой из этих концепций в том же порядке, что и они перечислены выше, поэтому он предпочитает расширение и когда вы вызываете ваш метод как test.method(new ArrayList<Integer>()); , компилятор находит что ArrayList<Integer>() можно расширить до Collection<?>, и поскольку он имеет наивысший приоритет, он вызывает эту версию и пренебрегает другими Примечание: если вы измените объявление двух других методов на private void overloadedMethod(ArrayList<?> o) и private void overloadedMethod(List<?> o), компилятор также выведет версию Collection<?>, потому что это предпочтительный