Шаг 43.
Язык программирования Java.
Обратные вызовы

На этом шаге мы поговорим про обратные вызовы

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

Рассмотрим следующий пример. В пакет javax.swing входит класс Timer, который можно использовать для отсечения интервалов времени. Так, если в программе предусмотрены часы, то с помощью класса Timer можно отсчитывать каждую секунду и обновлять циферблат часов. При установке таймера задается интервал времени и указывается, что именно должно произойти по его истечении.

Возникает вопрос: Как же указать таймеру, что именно он должен делать? Во многих языках программирования для этого задается имя функции, которую таймер должен периодически вызывать. Но в классах из стандартной библиотеки Java применяется объектно-ориентированный подход: таймеру нужно передать объект некоторого класса. После этого таймер вызывает один из методов для данного объекта. Передача объекта - более гибкий механизм, чем вызов функции, поскольку объект может нести дополнительную информацию.

Разумеется, таймер должен знать, какой именно метод следует вызвать. Для этого таймеру нужно указать объект класса, реализующего интерфейс ActionListener из пакета java.awt.event. Содержимое этого интерфейса представлено ниже:

public interface ActionListener {
    void actionPerformed(ActionEvent event);
}

По истечении заданного интервала времени таймер вызывает метод actionPerformed(). Допустим, что через каждые десять секунд требуется выводить на экран сообщение о текущем времени, сопровождаемое звуковым сигналом. Для этого нужно сначала определить класс, реализующий интерфейс ActionListener, а затем ввести операторы, которые должны быть выполнены, в тело метода actionPerformed():

class TimerPrinter implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        Date now = new Date();
        System.out.println("now: " + now);
        Toolkit.getDefaultToolkit().beep();
    }
}

Обратите внимание на параметр ActionEvent метода actionPerformed(). Он содержит сведения о событии, например, об инициировавшем его объекте (более подробнее об этом мы поговорим позднее). В данном примере подробные сведения о событии не важны.

Затем нужно сконструировать объект данного класса и передать его конструктору класса Timer следующим образом:

ActionListener listener = new TimerPrinter();
Timer timer = new Timer(10000, listener);

Первый параметр конструктора Timer представляет собой измеряемый в миллисекундах интервал времени между последовательными уведомлениями. Сообщение о текущем времени должно выводиться каждые десять секунд. А второй параметр является объектом класса ActionListener.

И наконец, таймер запускается следующим образом:

timer.start();

Приведем ниже исходный текст программы демонстрирующий использование обратных вызовов.

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

/**
 * <p>Класс TimerTest для тестирования таймера</p>
 * <p>Функция showMessageDialog класса JOptionPane создает диплоговое окно, в котором
 * предлагается завершить программу</p>
 * */
public class TimerTest {
    public static void main(String[] args) {
        ActionListener listener = new TimerPrinter();
        Timer timer = new Timer(10000, listener);
        timer.start();

        JOptionPane.showMessageDialog(null, "Quit program?");
    }
}

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

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


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


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

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

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