16 июл. 2015 г.

Интерфейсы. Часть 3 – наследование в интерфейсах.

Ключевое слово extends позволяет одному интерфейсу наследовать другой. Синтаксис определения такого наследования аналогичен синтаксису наследования классов, но в отличие от них интерфейсы могут наследоваться от любого множества интерфейсов, а не от одного как классы.
Интерфейс, который расширяет (наследуется) более одного интерфейса, наследует все методы и константы от каждого родителя и может определять собственные дополнительные абстрактные методы и константы.
Когда класс реализует интерфейс, который наследует другие интерфейсы, он должен предоставлять реализации всех методов, определенных внутри цепочки наследования интерфейса.
Приведем простой пример. На котором, я кстати покажу, что интерфейсы и классы могут содержаться в одном java файле, но в таком случае только один класс может быть public, остальные должны быть с пакетным доступом. Эффект ничем не отличается от создания отдельного java-файла для каждого класса и интерфейса. После компиляции получаются отдельные class файлы для каждого интерфейса и класса.

В этом примере интерфейс В наследуется от интерфейса А, в котором определены два метода с реализациями по умолчанию. В интерфейса В определен один метод без реализации по умолчанию.
Как видим в классе Ext1 мы реализовали только метод methB1(), поскольку для него нет реализации по умолчанию. Другие же методы – methA1() и methA2() были унаследованы в своей реализации по умолчанию.
В классе Ext2 мы реализовали все методы интерфейсов А и В переопределив их по своему.
Внимание стоит обратить на строки 54 и 58, где мы создаем объектные интерфейсные ссылки ext2 и ext3 соответственно. Но ссылка ext3 имеет интерфейсный тип А, именно поэтому на ней нельзя вызывать метод methB2(), хотя он у нас и реализован в классе Ext2.
Вывод у программы следующий:
I0018
GrabliДалее в наследовании интерфейсов начинаются грабельки. А что если в каком либо из родителей и потомков объявлены методы с одинаковой сигнатурой? А что если параметры методов совпадают, но отличается тип возвращаемого значения? И т.д и т.п.
Попробуем со всем этим разобраться… Хотя, возможно, все случаи тут и не перечислю, так как их достаточно много, но основные идеи постараюсь донести. А на остальные случаи грабли вам в помощь :)
  • Если класс реализует интерфейсы в которых есть методы с одинаковой сигнатурой и возвращаемым значением, но сам не переопределяет реализацию этих одинаковых методов, то тогда возникнет ошибка компиляции. Если же он переопределяет эти методы, то тогда все нормально.
  • Если в интерфейсах наследуемых один от другого есть одинаковые методы с реализациями по умолчанию, то предпочтение отдается реализации самого нижнего метода по умолчанию в цепочке, так как действует правило переопределения методов. Но если в классе переопределена реализация этого метода, то предпочтение отдается реализации метода в классе. Это естественное правило. Но благодаря новой форме ключевого слова super, можно обратиться к реализации метода по умолчанию родительского интерфейса из метода интерфейса наследника. Эта форма ключевого слова super выглядит следующим образом:

    имя_интерфейса.super.имя_метода();
    Если, допустим, из метода с реализацией по умолчанию интрефейса В, который унаследовался от интерфейса А, надо обратиться к методу по умолчанию интерфейса А, то это может выглядеть например так:

    A.super
.method();
  • Если наследуемые методы интерфейсов имеют одинаковые параметры, но различный тип возвращаемого значения, то возникает ошибка компиляции.

  • Теперь посмотрим это на примере:

    Программа генерирует следующий вывод:
    I0019
    Первые четыре строки генерируются имплементацией метода по умолчанию meth() интерфейса D, вызванные на объекте класса Dd. Последняя строка выводится имплементацией метода meth() в классе Cb вызванного на объекте этого класса. Опять же, обратите внимание на строки 47 и 50, на то каким образом определены типы ссылок.

    3 комментария:

    1. Здравствуйте, если есть возможность, уберите точку с запятой в 31 и 36 строках первого примера. Те, кто первый раз разбирается с интерфейсами, взорвут себе мозг пытаясь разобраться с таким синтаксисом.

      ОтветитьУдалить
    2. Да, они там действительно лишние, но на работоспособоность кода это ни как не влияет.

      ОтветитьУдалить