Страницы

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

воскресенье, 14 апреля 2019 г.

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

Есть некий обобщенный интерфейс и класс, его реализующий.
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) дергают и предупреждает, что надо бы тип передать. А то что тип передали в класс, который будет всю работу делать от него скрыто.
Я правильно всё понял?


Ответ

Суть тут в том, что вы явно не указали, какой тип в дженерике будет, то есть компилятор не знает об этом, а это чревато ошибкой в рантайме. То есть в приведеном вами коде можно написать так:
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-метод параметр будет проверен на этапе компиляции и не даст вам выстрелить в ногу.
Рекомендую

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

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