Интерфейс, который расширяет (наследуется) более одного интерфейса, наследует все методы и константы от каждого родителя и может определять собственные дополнительные абстрактные методы и константы.
Когда класс реализует интерфейс, который наследует другие интерфейсы, он должен предоставлять реализации всех методов, определенных внутри цепочки наследования интерфейса.
Приведем простой пример. На котором, я кстати покажу, что интерфейсы и классы могут содержаться в одном java файле, но в таком случае только один класс может быть public, остальные должны быть с пакетным доступом. Эффект ничем не отличается от создания отдельного java-файла для каждого класса и интерфейса. После компиляции получаются отдельные class файлы для каждого интерфейса и класса.
В этом примере интерфейс В наследуется от интерфейса А, в котором определены два метода с реализациями по умолчанию. В интерфейса В определен один метод без реализации по умолчанию.
Как видим в классе Ext1 мы реализовали только метод methB1(), поскольку для него нет реализации по умолчанию. Другие же методы – methA1() и methA2() были унаследованы в своей реализации по умолчанию.
В классе Ext2 мы реализовали все методы интерфейсов А и В переопределив их по своему.
Внимание стоит обратить на строки 54 и 58, где мы создаем объектные интерфейсные ссылки ext2 и ext3 соответственно. Но ссылка ext3 имеет интерфейсный тип А, именно поэтому на ней нельзя вызывать метод methB2(), хотя он у нас и реализован в классе Ext2.
Вывод у программы следующий:
Далее в наследовании интерфейсов начинаются грабельки. А что если в каком либо из родителей и потомков объявлены методы с одинаковой сигнатурой? А что если параметры методов совпадают, но отличается тип возвращаемого значения? И т.д и т.п.
Попробуем со всем этим разобраться… Хотя, возможно, все случаи тут и не перечислю, так как их достаточно много, но основные идеи постараюсь донести. А на остальные случаи грабли вам в помощь :)
- Если класс реализует интерфейсы в которых есть методы с одинаковой сигнатурой и возвращаемым значением, но сам не переопределяет реализацию этих одинаковых методов, то тогда возникнет ошибка компиляции. Если же он переопределяет эти методы, то тогда все нормально.
- Если в интерфейсах наследуемых один от другого есть одинаковые методы с реализациями по умолчанию, то предпочтение отдается реализации самого нижнего метода по умолчанию в цепочке, так как действует правило переопределения методов. Но если в классе переопределена реализация этого метода, то предпочтение отдается реализации метода в классе. Это естественное правило. Но благодаря новой форме ключевого слова super, можно обратиться к реализации метода по умолчанию родительского интерфейса из метода интерфейса наследника. Эта форма ключевого слова super выглядит следующим образом:
имя_интерфейса.super.имя_метода();
Если, допустим, из метода с реализацией по умолчанию интрефейса В, который унаследовался от интерфейса А, надо обратиться к методу по умолчанию интерфейса А, то это может выглядеть например так:
A.super
Теперь посмотрим это на примере:
Программа генерирует следующий вывод:
Первые четыре строки генерируются имплементацией метода по умолчанию meth() интерфейса D, вызванные на объекте класса Dd. Последняя строка выводится имплементацией метода meth() в классе Cb вызванного на объекте этого класса. Опять же, обратите внимание на строки 47 и 50, на то каким образом определены типы ссылок.
Здравствуйте, если есть возможность, уберите точку с запятой в 31 и 36 строках первого примера. Те, кто первый раз разбирается с интерфейсами, взорвут себе мозг пытаясь разобраться с таким синтаксисом.
ОтветитьУдалитьДа, они там действительно лишние, но на работоспособоность кода это ни как не влияет.
ОтветитьУдалитьТочку запятой убрал.
ОтветитьУдалитьНе вижу кода. Почему?
ОтветитьУдалитьВот пример №1:
ОтветитьУдалить```java
package pro.java.multiext01;
import static pro.java.util.Print.*;
interface A {
default void methA1() {
println("Method A1");
}
default void methA2() {
println("Method A2");
}
}
interface B extends A {
void methB1();
}
class Ext1 implements B {
@Override
public void methB1() {
print("Метод В1");
}
}
class Ext2 implements B {
@Override
public void methA1() {
println("Метод A1");
}
@Override
public void methA2() {
println("Метод A2");
}
@Override
public void methB1() {
print("Метод В1");
}
}
public class MulitEx {
public static void main(String[] args) {
Ext1 ext1 = new Ext1();
ext1.methA1();
ext1.methA2();
ext1.methB1();
printLnLineLn();
B ext2 = new Ext2(); // внимание сюда
ext2.methA1();
ext2.methA2();
ext2.methB1();
A ext3 = new Ext2(); // внимание сюда
printLnLineLn();
ext3.methA1();
ext3.methA2();
// ext3.methB1(); // ОШИБКА
}
}
```