Множественное наследование в Java
Interface это не просто более чистая форма абстрактного класса. Он имее более "высокое" применение. Поскольку interface не имеет реализации всего, что есть в нтем, то нет и массива-хранилища связанного с ним, нет ничего мешающего для комбинации нескольких интерфейсов. И это ценно, поскольку иногда вам требуется нечто: "x есть a и b и c." В C++, этот акт множественных интерфейсов называется множественное наследование, и при этом этот тип тянет за собой "прилипший" багаж, поскольку каждый тип имеет свою реализацию. В Java Вы можете осуществить то же самое, но только один из этих классов может иметь реализацию, так что проблемы, возникающие в C++, не возникают в Java, при комбинировании множества интерфейсов:
В дочерних классах, Вы не можете насильно получить доступ к базовому классу, поскольку он так же абстрактен и монолитен - нерушим (один без абстрактных методов). Если Вы наследуете не от интерфейса, Вы можете наследовать только от него одного. Все остальные из элементов базового класса должны быть интерфейсами. Вы помещаете имена всех интерфейсов после ключевого слова implements и разделяете их при помощи запятых. Вы можете использовать столько интерфейсов, сколько хотите, каждый из них становится независимым типом, к которому Вы в последствии можете привести. Следующий пример демонстрирует комбинирование класса с несколькими интерфейсами для создания нового класса:
//: c08:Adventure.java
// Множество интерфейсов.
import java.util.*;
interface CanFight { void fight(); }
interface CanSwim { void swim(); }
interface CanFly { void fly(); }
class ActionCharacter { public void fight() {} }
class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} }
public class Adventure { static void t(CanFight x) { x.fight(); } static void u(CanSwim x) { x.swim(); } static void v(CanFly x) { x.fly(); } static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Treat - CanFight
u(h); // Treat - CanSwim
v(h); // Treat - CanFly
w(h); // Treat - ActionCharacter
} } ///:~
В этом примере, как Вы можете видеть, класс Hero комбинирует конкретный класс ActionCharacter с интерфейсами CanFight, CanSwim и CanFly. Когда Вы комбинируете именованный класс с интерфейсами, как в этом примере, этот класс должен быть указан первым, а только затем интерфейсы, в противном случае компилятор выдаст сообщение об ошибке.
Заметьте, что сигнатура fight( ) та же самая, в интерфейсе CanFight и в классе ActionCharacter, но обратите внимание, что fight( ) не определена в Hero. Правилом для интерфейса является то, что Вы можете наследовать от него, но тогда Вы получите еще один интерфейс. Если же Вы хотите создать объект нового типа, то это должен быть класс со всеми определениями. Даже в силу того, что Hero не предоставляет определения для fight( ), это определение появляется вместе с ActionCharacter. Поскольку оно предоставляется автоматически и есть возможность создать объект от Hero.
В классе Adventure, Вы можете видеть, что в нем есть несколько методов, которые воспринимают в качестве аргументов различные интерфейсы и конкретные классы. Когда объект Hero уже создан, то он может быть передан в качестве параметра в любой их этих методов, что в свою очередь означает, что он может быть приведен к базовому типу к любому из вышеописанных интерфейсов. Поскольку мы рассматриваем путь создания интерфейсов в Java, то на этой дороге программисту не встретится никаких особенных трудностей и не придется специально напрягаться.
Запомните пожалуйста причину использования интерфейсов, кратко ее можно изложить так: возможность приведения к более, чем одному базовому типу. В дополнение вторая причина для использования интерфейсов в том же, в чем и причина использования абстрактных базовых классов: предотвращение создания объектов этого класса программистами и понимания, что это всего лишь интерфейс. Отсюда возникает вопрос: Что Вы должны использовать? Interface или abstract класс? Интерфейс дает вам преимущества абстрактного класса и преимущества интерфейса, так что если нужно создать базовый класс без любых определений методов или переменных, то Вы должны предпочесть абстрактному классу интерфейс. В действительности, если Вы знаете, что что-то собирается стать базовым классом, вашим первым решением должно быть - использовать интерфейс и если только Вы решите, что этот класс должен иметь определения методов и переменных, только тогда Вы должны изменить его на абстрактный класс или если это так необходимо на обычный класс.