interface DangerousMonster extends Monster { void destroy();
}
interface Lethal { void kill();
}
class DragonZilla implements DangerousMonster { public void menaceО {} public void destroyО {}
}
interface Vampire extends DangerousMonster, Lethal { void drinkBloodO;
}
class VeryBadVampire implements Vampire { public void menaceO {} public void destroyО {} public void killO {} public void drinkBloodO {}
}
public class HorrorShow {
static void u(Monster b) { b.menaceO; } static void v(DangerousMonster d) { d. menaceO, d.destroyО;
}
static void w(Lethal 1) { 1 killO; } public static void main(String[] args) {
DangerousMonster barney = new DragonZi11a(); u(barney); v(barney);
Vampire vlad = new VeryBadVampire(); u(vlad), v(vlad); w(vlad);
}
} ///:-
DangerousMonster представляет собой простое расширение Monster, в результате которого образуется новый интерфейс. Он реализуется классом DragonZilla.
Синтаксис, использованный в интерфейсе Vampire, работает
Конфликты имен при совмещении интерфейсов
При реализации нескольких интерфейсов может возникнуть небольшая проблема. В только что рассмотренном примере интерфейс CanFight и класс Action-Character имеют идентичные методы void fight(). Хорошо, если методы полностью тождественны, но что, если они различаются по сигнатуре или типу возвращаемого значения? Рассмотрим такой пример:
//• i interfaces/InterfaceColli si on java package interfaces;
interface II { void f(); }
interface 12 { int f(int i); }
interface 13 { int f(). }
class С { public int f() { return 1; } }
class C2 implements II. 12 { public void f() {}
public int f(int i) { return 1; } // перегружен
}
class C3 extends С implements 12 {
public int f(int i) { return 1; } // перегружен
}
class C4 extends С implements 13 { // Идентичны, все нормально; public int f() { return 1; }
}
// Методы различаются только по типу возвращаемого значения; //! class С5 extends С implements II {} //! interface 14 extends II. 13 {} ///;-
Трудность возникает из-за того, что переопределение, реализация и перегрузка образуют опасную «смесь». Кроме того, перегруженные методы не могут различаться только возвращаемыми значениями. Если убрать комментарий в двух последних строках программы, сообщение об ошибке разъясняет суть происходящего:
InterfaceCollisi on.java.23 f() в С не может реализовать f() в II; попытка использовать несовместимые возвращаемые типы обнаружено: int требуется- void
InterfaceCollisi on java;24- интерфейсы 13 и II несовместимы; оба определяют f(). но с различными возвращаемыми типами
Использование одинаковых имен методов в интерфейсах, предназначенных для совмещения, обычно приводит к запутанному и трудному для чтения коду. Постарайтесь по возможности избегать таких ситуаций.
Интерфейсы как средство адаптации
Одной из самых убедительных причин для использования интерфейсов является возможность определения нескольких реализаций для одного интерфейса. В простых ситуациях такая схема принимает вид метода, который при вызове передается интерфейсу; от вас потребуется реализовать интерфейс и передать объект методу.
Соответственно, интерфейсы часто применяются в архитектурном паттерне
Например, конструктор класса Java SE5 Scanner получает интерфейс Readable. Анализ показывает, что Readable не является аргументом любого другого метода из стандартной библиотеки Java — этот интерфейс создавался исключительно для Scanner, чтобы его аргументы не ограничивались определенным классом. При таком подходе можно заставить Scanner работать с другими типами. Если вы хотите создать новый класс, который может использоваться со Scanner, реализуйте в нем интерфейс Readable:
//. interfaces/RandomWords java
// Реализация интерфейса для выполнения требований метода
import java nio.*;
import java util.*,
public class RandomWords implements Readable { private static Random rand = new Random(47); private static final char[] capitals =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private static final char[] lowers =
"abcdefghijklmnopqrstuvwxyz".toCharArrayO; private static final char[] vowels =
"aeiou" toCharArrayO; private int count,
public RandomWords(int count) { this.count = count: } public int read(CharBuffer cb) { if(count-- == 0)
return -1; // Признак конца входных данных cb.append(capi tals[rand.nextInt(capi ta1s.1 ength) ]); for(int i = 0; i < 4; i++) {
cb.append(vowels[rand.nextInt(vowels.1ength)]); cb append(lowers[rand.nextInt(lowers.length)]),
}