Рефераты. Интерфейсы, обратные вызовы, внутренние классы

Затем, в фигурных скобках, записываются в любом порядке константы и заголовки методов. Можно сказать, что в интерфейсе все методы абстрактные, но слово abstract писать не надо. Константы всегда статические, но слова static и final указывать не нужно.

Все константы и методы в интерфейсах всегда открыты, не надо даже указывать модификатор public.

Вот какую схему можно предложить для иерархии автомобилей:

interface Automobile{ . . . }

interface Car extends Automobile{ . . . }

interface Truck extends Automobile{ . . . }

interface Pickup extends Car, Truck{ . . . }

Таким образом, интерфейс -- это только набросок, эскиз. В нем указано, что делать, но не указано, как это делать.

Как же использовать интерфейс, если он полностью абстрактен, в нем нет ни одного полного метода?

Использовать нужно не интерфейс, а его реализацию (implementation). Реализация интерфейса -- это класс, в котором расписываются методы одного или нескольких интерфейсов. В заголовке класса после его имени или после имени его суперкласса, если он есть, записывается слово implements и, через запятую, перечисляются имена интерфейсов.

Вот как можно реализовать иерархию автомобилей:

interface Automobile{ . . . }

interface Car extends Automobile! . . . }

class Truck implements Automobile! . . . }

class Pickup extends Truck implements Car{ . . . }

или так:

interface Automobile{ . . . }

interface Car extends Automobile{ . . . }

interface Truck extends Automobile{ . . . }

class Pickup implements Car, Truck{ . . . }

Реализация интерфейса может быть неполной, некоторые методы интерфейса расписаны, а другие -- нет. Такая реализация -- абстрактный класс, его обязательно надо пометить модификатором abstract.

Как реализовать в классе Рickup метод f(), описанный и в интерфейсе саг, и в интерфейсе Truck с одинаковой сигнатурой? Ответ простой -- никак. Такую ситуацию нельзя реализовать в классе Pickup. Программу надо спроектировать по-другому.

Итак, интерфейсы позволяют реализовать средствами Java чистое объектно-ориентированное проектирование, не отвлекаясь на вопросы реализации проекта.

Мы можем, приступая к разработке проекта, записать его в виде иерархии интерфейсов, не думая о реализации, а затем построить по этому проекту иерархию классов, учитывая ограничения одиночного наследования и видимости членов классов.

Интересно то, что мы можем создавать ссылки на интерфейсы. Конечно, указывать такая ссылка может только на какую-нибудь реализацию интерфейса. Тем самым мы получаем еще один способ организации полиморфизма.

Листинг П.3 показывает, как можно собрать с помощью интерфейса «хор» домашних животных.

Листинг П.3. Использование интерфейса для организации полиморфизма

interface Voice{

void voice();

}

class Dog implements Voice{

public void voice (){

System.out.println("Gav-gav!");

}

}

class Cat implements Voice{

public void voice (){

System.out.println("Miaou!");

}

}

class Cow implements Voice{

public void voice(){

System.out.println("Mu-u-u!");

}

}

public class Chorus{

public static void main(String[] args){

Voiced singer = new Voice[3];

singer[0] = new Dog();

singer[1] = new Cat();

singer[2] = new Cow();

for(int i = 0; i < singer.length; i++)

singer[i].voice();

}

}

Здесь используется интерфейс voice .

Что же лучше использовать: абстрактный класс или интерфейс? На этот вопрос нет однозначного ответа.

Создавая абстрактный класс, вы волей-неволей погружаете его в иерархию классов, связанную условиями одиночного наследования и единым предком -- классом Оbject. Пользуясь интерфейсами, вы можете свободно проектировать систему, не задумываясь об этих ограничениях.

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

Есть еще одно ограничение: все реализации методов интерфейсов должны быть открытыми, public, поскольку при переопределении можно лишь расширять доступ, а методы интерфейсов всегда открыты.

Вообще же наличие и классов, и интерфейсов дает разработчику богатые возможности проектирования. В нашем примере, вы можете включить в хор любой класс, просто реализовав в нем интерфейс voice.

Наконец, можно использовать интерфейсы просто для определения констант, как показано в листинге П.4.

Листинг П.4. Система управления светофором

interface Lights{

int RED = 0;

int YELLOW = 1;

int GREEN = 2;

int ERROR = -1;

}

class Timer implements Lights{

private int delay;

private static int light = RED;

Timer(int sec)(delay = 1000 * sec;}

public int shift(){

int count = (light++) % 3;

try{

switch(count){

case RED: Thread.sleep(delay); break;

case YELLOW: Thread.sleep(delay/3); break;

case GREEN: Thread.sleep(delay/2); break;

}

}catch(Exception e){return ERROR;}

return count;

}

}

class TrafficRegulator{

private static Timer t = new Timer(1);

public static void main(String[] args){

for (int k = 0; k < 10; k++)

switch(t.shift()){

case Lights.RED: System.out.println("Stop!"); break;

case Lights.YELLOW: System.out.println("Wait!"); break;

case Lights.GREEN: System.out.println("Go!"); break;

case Lights.ERROR: System.err.println("Time Error"); break;

default: System.err.println("Unknown light."); return;

}

}

}

Здесь, в интерфейсе Lights, определены константы, общие для всего проекта.

Класс Timer реализует этот интерфейс и использует константы напрямую как свои собственные. Метод shift () этого класса подает сигналы переключения светофору с разной задержкой в зависимости от цвета. Задержку осуществляет метод sleep() класса Thread из стандартной библиотеки, которому передается время задержки в миллисекундах. Этот метод нуждается в обработке исключений try{} catch() {}.

Класс TrafficReguiator не реализует интерфейс Lights и пользуется полными именами Lights.RED и т.д. Это возможно потому, что константы RED, YELLOW и GREEN по умолчанию являются статическими.

Приложение 2. Вложенные классы

В теле класса можно сделать описание другого, вложенного (nested) класса. А во вложенном классе можно снова описать вложенный, внутренний (inner) класс и т. д. Можно ли из вложенного класса обратиться к членам внешнего класса? Можно, для того это все и задумывалось.

· А можно ли в таком случае определить экземпляр вложенного класса, не определяя экземпляры внешнего класса? Нет, нельзя, сначала надо определить хоть один экземпляр внешнего класса, матрешка ведь!

· А если экземпляров внешнего класса несколько, как узнать, с каким экземпляром внешнего класса работает данный экземпляр вложенного класса? Имя экземпляра вложенного класса уточняется именем связанного с ним экземпляра внешнего класса. Более того, при создании вложенного экземпляра операция new тоже уточняется именем внешнего экземпляра.

Все вложенные классы можно разделить на вложенные классы-члены класса (member classes), описанные вне методов, и вложенные локальные классы (local classes), описанные внутри методов и/или блоков. Локальные классы, как и все локальные переменные, не являются членами класса.

Классы-члены могут быть объявлены статическим модификатором static. Поведение статических классов-членов ничем не отличается от поведения обычных классов, отличается только обращение к таким классам. Поэтому они называются вложенными классами верхнего уровня (nestee tep-level classes), хотя статические классы-члены можно вкладывать друг в друга. В них можно объявлять статические члены. Используются они обычно для того, чтобы сгруппировать вспомогательные классы вместе с основным классом.

Все нестатические вложенные классы называются внутренними (inner). В них нельзя объявлять статические члены.

Локальные классы, как и все локальные переменные, известны только в блоке, в котором они определены. Они могут быть безымянными (anonymous classes).

Пример.

Листинг Вложенные классы

class Nested{

static private int pr; // Переменная pr объявленa статической

// чтобы к ней был доступ из статических классов А и АВ

String s = "Member of Nested";

// Вкладываем статический класс.

static class .А{ // Полное имя этого класса -- Nested.A

private int a=pr;

String s = "Member of A";

// Во вложенньм класс А вкладываем еще один статический класс

static class AB{ // Полное имя класса -- Nested.А.АВ

private int ab=pr;

String s = "Member of AB";

}

}

//В класс Nested вкладываем нестатический класс

class В{ // Полное имя этого класса -- Nested.В

private int b=pr;

String s = "Member of B";

Страницы: 1, 2, 3, 4



2012 © Все права защищены
При использовании материалов активная ссылка на источник обязательна.