КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Абстрактные классы и интерфейсыАбстрактные классы объявляются с ключевым словомabstractи содержат объявления абстрактных методов, которые не реализованы в этих классах, а будут реализованы в подклассах. Объекты таких классов создать нельзя, но можно создать объекты подклассов, которые реализуют эти методы. Абстрактные классы могут содержать и полностью реализованные методы. Интерфейсы представляют полностью абстрактные классы: ни один из объявленных методов не может быть реализован. Все объявленные методы автоматически трактуются как public и abstract, а все атрибуты – как public, static и final. Каждый интерфейс может быть реализован одним или несколькими классами. Класс может реализовывать любое число интерфейсов, указываемых после ключевого слова implements, дополняющего определение класса. На множестве интерфейсов также определена иерархия по наследованию, но она не имеет отношения к иерархии классов. В языке Java интерфейсы обеспечивают большую часть той функциональности, которая в C++ представляется с помощью механизма множественного наследования. Определение интерфейса имеет вид: [public] interface имя [extendsI1,I2,…,IN]{/*реализация*/} Реализация интерфейсов классом может иметь вид: [доступ] class имя_класса implements I1,I2, …,IN {/*реализация класса*/} Здесь I1,I2, …,IN перечень используемых интерфейсов. Класс, который реализует интерфейс, должен предоставить полную реализацию всех методов, объявленных в интерфейсе. Кроме этого, данный класс может объявлять свои собственные методы. Если класс расширяет интерфейс, но полностью не реализует его методы, то этот класс должен быть объявлен как abstract. /* пример # 2 : интерфейс и его реализации : InterfacesDemo.java */ interface Auto{ String getMark();//объявление методов String getPassangers(); String getWheels(); } class Bus implements Auto{//реализация интерфейса public String getMark(){return "Mercedes";} public String getPassangers(){return "90 человек";} public String getWheels(){return "6 колес";} } class Car implements Auto{ public String getMark(){return "BMW";} public String getPassangers(){return "5 человек";} public String getWheels(){return "4 колеса";} } //метод getWheels() в следующем абстрактном классе не реализован abstract class Truck implements Auto{ public String getMark(){return "Renault";} public String getWheels(){return "24 колеса";} } public class InterfacesDemo { public static void main(String[] args){ Car c = new Car(); Bus b = new Bus(); printFeatures(c); printFeatures(b); } public static void printFeatures(Auto f){ System.out.println("марка:" + f.getMark() + " вместимость:" + f.getPassangers() + " количество колес: " + f.getWheels()); } } Класс InterfacesDemo содержит метод printFeatures(), который вызывает методы того объекта, который передается ему в качестве параметра. Вначале ему передается объект, соответствующий легковому автомобилю, затем автобусу (объекты с и b). Каким образом метод printFeatures() может обрабатывать объекты двух различных классов? Все дело в типе передаваемого этому методу аргумента – класса, реализующего интерфейс Auto. Вызывать, однако, можно только те методы, которые были объявлены в интерфейсе. В следующем примере объявляется объектная ссылка, которая использует интерфейсный тип. В такой переменной можно сохранять экземпляр любого класса, который реализует объявленный интерфейс. Когда вызывается метод через такую ссылку, то будет вызываться его правильная версия, основанная на текущем экземпляре. Выполняемый метод разыскивается динамически во время выполнения, что позволяет создавать классы позже кода, который вызывает их методы. // пример # 3 : динамический вызов методов : TestCall.java interface Call{ int NUMBER = 10; // final по умолчанию } interface Callback extendsCall{ void callB(); /* abstract по умолчанию */ //int i; // ошибка, если нет инициализации //void method(){/*код*/} // ошибка, т.к. абстрактный метод не //может иметь тела! } class Client implements Callback { public void callB() { System.out.println("метод callB() вызван со значением = " + NUMBER); } } class XClient implements Callback { public void callB() { System.out.print("другая версия метода callВ():"); System.out.println("NUMBER в квадрате = " + (NUMBER*NUMBER)); } } public class TestCall{ public static void main(String[] args) { Callback c = new Client();//ссылка на интерфейсный тип Client cl = new Client(); XClient ob = new XClient(); c.callB(); c = ob; // присваивается ссылка на другой объект c.callB(); //cl = ob;//ошибка! разные ветви наследования } } Результат: метод сallB() вызван со значением = 10 другая версия метода callB(): NUMBER в квадрате = 100 Кроме того, что нельзя присваивать значения ссылок, находящихся в разных цепочках наследования, по этой же причине ошибку вызовет операция типа Client cl = new XClient();
|