Java — реализация параметризованных интерфейсов

Приветствую всех изучающих Java!
На днях, ковыряя холодным осенним вечером Эккеля (Thinking in Java 4ed), окончательно во всем запутался. Читаю короткий абзац:
Реализация параметризованных интерфейсов
Класс не может реализовывать две разновидности одного параметризованного интерфейса — вследствие стирания они будут считаться одним и тем же интерфейсом. Пример конфликта такого рода:
interface Payable<T> {}

class Employee implements Payable<Employee> {}
class Hourly extends Employee implements Payable<Hourly> {}

Класс Hourly компилироваться не будет, потому что стирание сокращает Payable<Employee> и Payable<Hourly> до Payable, а в приведенном примере это означало бы двукратную реализацию одного интерфейса. Интересная подробность: если удалить параметризованные аргументы из обоих упоминаний Payable, как это делает компилятор при стирании, программа откомпилируется.
Сразу оговорюсь — ситуация не является боевой, просто хочется нормально разобраться с теорией.
Разумеется заподозрил неладное, накидал по-быстрому исходник в Eclips`e… работает, собака, как и сказано.
Если начать чистить селёдку так сказать с хвоста, то вопросов к последнему утверждению просто никаких:
если удалить параметризованные аргументы из обоих упоминаний Payable, как это делает компилятор при стирании, программа откомпилируется
То есть будет:
class Employee implements Payable {}
class Hourly extends Employee implements Payable {}
OK, все нормально, интерфейс один и тот же, интерфейсы не наследуются, а значит в иерархии наследования можно сколько угодно реализовывать один и тот же интерфейс.
Чистим брюхо селёдки:
… стирание сокращает Payable<Employee> и Payable<Hourly> до Payable…
таак, немного пожёстче. Стирание не позволяет получать информацию о типе внутри параметризованного кода, компилятор генерит обычный НЕпараметризованый байт-код. Хорошо, Payable<Employee> и Payable<Hourly> стираются до ближайшего ограничения (а ограничений на параметр типа у нас нет — interface Payable<T> {}) или до «низкоуровневого» типа Payable.
Приближаемся к голове селедки:
Класс не может реализовывать две разновидности одного параметризованного интерфейса — вследствие стирания они будут считаться одним и тем же интерфейсом
ну, здОрово, компилятор просто сотрёт Payable<Employee> и Payable<Hourly> до Payable и всё. Очевидно, не всё. И в довершение совершенно непонятная фраза:
… в приведенном примере это означало бы двукратную реализацию одного интерфейса.
Вот как сие понимать?
  • Вопрос задан
  • 16296 просмотров
Пригласить эксперта
Ответы на вопрос 2
becevka
@becevka
Вот вам кусочек кода для медитации:

    interface Payable<T> {
        void doIt(T t);
    }

    class Employee implements Payable<Employee> {
        @Override
        public void doIt(Employee t) {}
    }
    
    class Hourly extends Employee implements Payable<Hourly> {
        //что реализовать?
        @Override
        public void doIt(Employee t) {}
        // или
        @Override
        public void doIt(Hourly t) {}
    }
Ответ написан
Комментировать
rfq
@rfq
Программист
В сложных случаях надо обращаться к первоисточнику: Chapter 8. Classes, где сказано:

A class may not at the same time be a subtype of two interface types which are different invocations of the same generic interface (§9.1.2), or a subtype of an invocation of a generic interface and a raw type naming that same generic interface, or a compile-time error occurs.

This requirement was introduced in order to support translation by type erasure (§4.6).

А если неформально — то смысл тИповых параметров в том, чтобы статически сУзить допустимые типы для разных экземпляров отного и того же класса, так, чтобы у разных экземпляров сужение было разным.

В приведенном Вами коде используется два разных сужения: и :
class Employee implements Payable<Employee> {} class Hourly extends Employee implements Payable<Hourly> {}
которые невозможно совместить в одном экземпляре. Стирание тут при том, что если бы его не было, можно было бы попытаться расклеить интерфейсы и требовать двух реализаций каждого метода (имхо, плохая затея), а так у нас только один метод doIt и две разных сигнатуры.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы