Ильдар Хабибуллин - Java 7 [Наиболее полное руководство]
- Название:Java 7 [Наиболее полное руководство]
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2012
- ISBN:978-5-9775-0735-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Ильдар Хабибуллин - Java 7 [Наиболее полное руководство] краткое содержание
Java 7 [Наиболее полное руководство] - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Затем в фигурных скобках записываются в любом порядке константы и заголовки методов. Можно сказать, что в интерфейсе все методы абстрактные, но слово 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.
Как реализовать в классе Pickup метод f(), описанный и в интерфейсе Car, и в интерфейсе Truck с одинаковой сигнатурой? Ответ простой — никак. Такую ситуацию нельзя реализовать в классе Pickup. Программу надо спроектировать по-другому.
Итак, интерфейсы позволяют реализовать средствами Java чистое объектно-ориентированное проектирование, не отвлекаясь на вопросы реализации проекта.
Мы можем, приступая к разработке проекта, записать его в виде иерархии интерфейсов, не думая о реализации, а затем построить по этому проекту иерархию классов, учитывая ограничения одиночного наследования и видимости членов классов.
Интересно то, что мы можем создавать ссылки на интерфейсы. Конечно, указывать такая ссылка может только на какую-нибудь реализацию интерфейса. Тем самым мы получаем еще один способ организации полиморфизма.
Листинг 3.3 показывает, как можно собрать с помощью интерфейса "хор" домашних животных из листинга 2.2.
Листинг 3.3. Использование интерфейса для организации полиморфизма
interface Voice{ void voice();
}
class Dog implements Voice{
@Override
public void voice(){
System.out.println("Gav-gav!");
}
}
class Cat implements Voice{
@Override
public void voice(){
System.out.println("Miaou!");
}
}
class Cow implements Voice{
@Override
public void voice(){
System.out.println("Mu-u-u!");
}
} public class Chorus{
public static void main(String[] args){
Voice[] singer = new Voice[3]; singer[0] = new Dog(); singer[1] = new Cat(); singer[2] = new Cow(); for (Voice v: singer) v.voice();
}
}
Здесь используется интерфейс Voice вместо абстрактного класса Pet, описанного в листинге 2.2.
Что же лучше использовать: абстрактный класс или интерфейс? На этот вопрос нет однозначного ответа.
Создавая абстрактный класс, вы волей-неволей погружаете его в иерархию классов, связанную условиями одиночного наследования и единым предком — классом Object. Пользуясь интерфейсами, вы можете свободно проектировать систему, не задумываясь об этих ограничениях.
С другой стороны, в абстрактных классах можно сразу реализовать часть методов. Реализуя же интерфейсы, вы обречены на скучное переопределение всех методов.
Вы, наверное, заметили и еще одно ограничение: все реализации методов интерфейсов должны быть открытыми, public, поскольку при переопределении методов можно лишь расширять доступ к ним, а методы интерфейсов всегда открыты.
Вообще же наличие и классов, и интерфейсов дает разработчику богатые возможности проектирования. В нашем примере вы можете включить в хор любой класс, просто реализовав в нем интерфейс Voice.
Наконец, можно использовать интерфейсы просто для определения констант, как показано в листинге 3.4.
Листинг 3.4. Система управления светофором
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){
System.out.println("Stop!"); break;
System.out.println("Wait!"); break; System.out.println("Walk!"); break; System.err.println("Time Error"); break; System.err.println("Unknown light."); return;
for(int k = 0; k < 10; k++) switch(t.shift()){ case Lights.RED: case Lights.YELLOW: case Lights.GREEN: case Lights.ERROR: default:
}
}
Здесь, в интерфейсе Lights, определены константы, общие для всего проекта.
Класс Timer реализует этот интерфейс и использует константы напрямую как свои собственные. Метод shift() этого класса подает сигналы переключения светофору с разной задержкой в зависимости от цвета. Задержку осуществляет метод sleep () класса Thread из стандартной библиотеки, которому передается время задержки в миллисекундах. Этот метод нуждается в обработке исключений try{}catch(){}, о которой мы будем говорить в главе 21.
Класс TrafficRegulator не реализует интерфейс Lights и пользуется полными именами Lights.RED и т. д. Это возможно потому, что константы RED, YELLOW и GREEN по умолчанию являются статическими.
Перечисления
Просматривая листинг 3.4, вы, наверное, заметили, что создавать интерфейс только для записи констант не совсем удобно. Начиная с версии Java SE 5 для этой цели в язык введены перечисления (enumerations). Создавая перечисление, мы сразу же указываем константы, входящие в него. Вместо интерфейса Lights, описанного в листинге 3.4, можно воспользоваться перечислением, сделав такую запись:
enum Lights{ RED, YELLOW, GREEN, ERROR }
Как видите, запись сильно упростилась. Мы записываем только константы, не указывая их характеристики. Каков же, в таком случае, их тип? У них тип перечисления Lights.
Перечисления в языке Java образуют самостоятельные типы, что указывается словом enum в описании перечисления, но все они неявно наследуют абстрактный класс java.lang.Enum. Это наследование не надо указывать словом extends, как мы обычно делаем, определяя классы. Оно введено только для того, чтобы включить перечисления в иерархию классов Java API. Тем не менее мы можем воспользоваться методами класса Enum для получения некоторых характеристик перечисления, как показано в листинге 3.5.
enum Lights { RED, YELLOW, GREEN, ERROR }
public class EnumMethods{
public static void main(String[] args){ for (Lights light: Lights.values()){
System.out.println("Тип: " + light.getDeclaringClass());
System.out.println("4HcnoBoe значение: " + light.ordinal());
Читать дальшеИнтервал:
Закладка: