Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

java compiler, generics и наследование

#java


Есть некий обобщенный интерфейс и класс, его реализующий.

interface Contract {
    void doIt(T arg);
}

class Impl implements Contract {

    @Override
    public void doIt(Integer arg) {
        System.out.println("hi");
    }
}


При создании экземпляра Impl и вызове метода следующим образом

Contract obj = new Impl();
obj.doIt(42);


компилятор вежливо предупреждает, что Unchecked call ... . 

Я сделал следующий вывод - компилятор не смотрит на то, метод какого класса будет
фактически вызван. Вот смотрит он что Contract#doIt(T arg) дергают и предупреждает,
что надо бы тип передать. А то что тип передали в класс, который будет всю работу делать
от него скрыто.

Я правильно всё понял?
    


Ответы

Ответ 1



Суть тут в том, что вы явно не указали, какой тип в дженерике будет, то есть компилятор не знает об этом, а это чревато ошибкой в рантайме. То есть в приведеном вами коде можно написать так: Contract obj = new Impl(); obj.doIt("123"); //можно передать String и компилятор это съест Но когда вы запустите этот код, вы получите ClassCastException. Почему? Потому что в случае с дженериком в параметре метода компилятор создает так называемый bridge-метод и после компиляции ваш класс Impl будет иметь 2 метода: public void doIt(Integer arg) { System.out.println("hi"); } public void doIt(Object arg) { doIt((Integer) arg); //тут ClassCastException } компилятор вежливо предупреждает, что Unchecked call Собственно, предупреждает, потому что если вы напишите вот так: Contract obj = new Impl(); то передаваемый в этот bridge-метод параметр будет проверен на этапе компиляции и не даст вам выстрелить в ногу. Рекомендую

Комментариев нет:

Отправить комментарий