
- •Использование абстрактных классов
- •// Простая демонстрация абстракций Java.
- •Использование final для отказа от переопределения
- •Void meth() { // ошибка! Нельзя переопределять.
- •Использование final для отмены наследования
- •Интерфейсы
- •IntStack mystack; //создать ссылочную переменную
- •Интерфейсы и обратные вызовы (Хорстманн стр. 253 (279-new))
- •Внутренние классы (Хорстманн стр. 282-new)
Внутренние классы (Хорстманн стр. 282-new)
Внутренним (inner) называется класс, определенный внутри другого класса. Внутренние классы удобно использовать в следующих случаях:
необходимо обеспечить доступ к реализации объекта, который создал данный объект, включая закрытые данные;
необходимо скрыть данный класс от других классов того же пакета
при создании событийно-управляемых программ (анонимные внутренние классы ) .
Рассмотрим пример. (InnerClassTest.java)
/* version 1.10 2004-02-27 author Cay Horstmann */
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class InnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock(1000, true);
clock.start();
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class TalkingClock
{
private int interval;
private boolean beep;
public TalkingClock(int interval, boolean beep)
{
this.interval = interval;
this.beep = beep;
}
public void start()
{
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
private class TimePrinter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
Date now = new Date();
System.out.println("At the tone, the time is " + now);
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
Класс TimePrinter расположен в классе TalkingClock. Объекты TimePrinter создаются с методами класса TalkingClock.
TimePrinter представляет собой закрытый внутренний класс в составе TalkingClock. В результате создавать объекты TimePrinter могут только методы класса TalkingClock. Если бы TimePrinter был обычным классом, он должен был бы получить доступ к флагу beep посредством общедоступного метода. Наличие внутреннего класса делает это не обязательным при том же уровне безопасности.
Для определения анонимного внутреннего класса характерно следующее:
класс определяется локально в отдельном методе внешнего класса;
при объявлении класса не используются модификаторы доступа (public, protected). Их область видимости ограничена блоком в котором они объявлены;
методы анонимного класса могут ссылаться на локальные переменные объявленные как final;
в общем случае синтаксис определения анонимного класса выглядит следующим образом:
new СуперТип (параметры, необходимые для создания объекта)
{
Методы внутреннего класса и данные.
}
СуперТип – это или интерфейс (если внутренний класс реализует интерфейс), или класс (тогда внутренний класс расширяет данный суперкласс)
анонимный класс не может иметь конструкторов.
Анонимные внутренние классы довольно часто используются при создании событийно-управляемых программ. Это касается программного кода, который генерируется оболочкой языка (например NetBeans) при макетировании панели диалога и обработки событий от элементов управления.
Пример AnonymousInnerClassTest.java демонстрирует использование анонимного внутреннего класса.
/* version 1.10 2004-02-27 author Cay Horstmann */
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class AnonymousInnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock();
clock.start(1000, true);
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class TalkingClock
{
public void start(int interval, final boolean beep)
{
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
Date now = new Date();
System.out.println("At the tone, the time is " + now);
if (beep) Toolkit.getDefaultToolkit().beep();
}
};
Timer t = new Timer(interval, listener);
t.start();
}
}
Рассмотрим некоторые детали.
Вызывается метод clock.start(1000, true);
Инициализируется объектная переменная listener
Ссылка listener передается конструктору класса Timer, таймер запускается и метод start() прекращает свою работу. В этот момент параметр beep метода start() больше не существует.
Впоследствии (по истечении интервала таймера) вызывается метод actionPerformed() он выполняет оператор if (beep) . . . и . . .???
Чтобы метод actionPerformed() выполнялся успешно анонимный класс должен создать копию поля beep до того как оно перестанет существовать в качестве локальной переменной метода start(). Это и происходит.