Шаг 45.
Язык программирования Java.
Доступ к состоянию объекта из внутреннего класса

На этом шаге мы поговорим про доступ к состоянию объекта из внутреннего класса

Синтаксис, применяемый для внутренних классов, довольно сложен. Рассмотрим простой пример. Реорганизуем класс TimerTest из рассмотренного ранее примера, чтобы сформировать из него класс TalkingClock. Для организации работы "говорящих часов" применяются два параметра: интервал между последовательными сообщениями и признак, позволяющий включать или отключать звуковой сигнал. Ниже приведен шаблон нужного нам класса TalkingClock.

public class TalkingClock {
    private int interval;
    private boolean beep;

    public TalkingClock(int interval, boolean beep) {
        ...
    }
    public void start() {
        ...
    }
    public class TimerPrinter implements ActionListener {
        ...
    }
}

Обратим внимание на то, что класс TimerPrinter теперь расположен в классе TalkingClock. Это не означает, что каждый экземпляр класса TalkingClock содержит поле типа TimerPrinter. Объекты типа TimerPrinter создаются методами из класса TalkingClock.

Рассмотрим теперь класс TimerPrinter более подробно.

public class TimePrinter implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        Date now = new Date();
        System.out.println("now " + now);
        if (beep) {
            Toolkit.getDefaultToolkit().beep();
        }
    }
}

Обратим внимание, что теперь в методе actionPerformed() проверяется признак beep, который нам говорит воспроизводить ли звуковой сигнал. Заметим, что в классе TimerPrinter отсутствует поле beep. Вместо этого метод actionPerformed() обращается к соответствующему полю объекта типа TalkingClock. Оказывается, что внутренний класс имеет доступ не только к своим полям, но и к полям создавшего его объекта, то есть экземпляра внешнего класса. Это происходит потому что внутренний класс содержит ссылку на объект внешнего класса, хотя эта ссылка не присутствует явно.

Приведем ниже исходный код завершенного варианта программы, проверяющей внутренний класс. Если бы TimerPrinter был бы обычным классом, он должен был бы получить доступ к признаку beep через открытый метод из класса TalkingClock. Применение внутреннего класса усовершенствует код, поскольку отпадает необходимость предоставлять специальный метод доступа, представляющий интерес только для какого-нибудь другого класса.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;

/**
 * <p>Класс для тестирования программы</p>
 * */
public class ClassTest {
    public static void main(String[] args) {
        TalkingClock clock = new TalkingClock(1000, true);
        clock.start();

        JOptionPane.showMessageDialog(null, "Quit program");
        System.exit(0); /*Нужна для корректного завершения программы*/
    }
}

/**
 * <p>Класс для говорящих часов</p>
 * */
class TalkingClock {
    private int interval;
    private boolean beep;

    /**
     * <p>Конструктор класса TalkingClock</p>
     * @param interval Интервал вывода текущего времени
     * @param beep Подавать ли звук при выводе времени
     * */
    public TalkingClock(int interval, boolean beep) {
        this.interval = interval;
        this.beep = beep;
    }

    /**
     * <p>Функция для запуска часов</p>
     * */
    public void start()
    {
        ActionListener listener = new TimerPrinter();
        Timer timer = new Timer(interval, listener);
        timer.start();
    }

    /**
     * <p>Внутренний класс TimerPrinter</p>
     * */
    public class TimerPrinter implements ActionListener {
        /**
         * <p>Функция из интерфейса ActionListener</p>
         * @param e Событие, которое побуждает вызов функции actionPerformed
         * */
        @Override
        public void actionPerformed(ActionEvent e) {
            Date now = new Date();
            System.out.println("At the tone, the time is " + now);
            if (beep) {
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }
}

Проект можно взять здесь


Рис. 1. Окно сообщения


Рис. 2. Вывод программы

На следующем шаге мы рассмотрим синтаксические правила для внутренних классов

Предыдущий шаг Содержание Следующий шаг