Что такое callback java
Одним из распространенных способов использования интерфейсов в Java является создание обратного вызова. Суть обратного вызова состоит в том, что мы создаем действия, которые вызываются при других действиях. То есть одни действия вызываются другими действиями. Стандартный пример — нажатие на кнопку. Когда мы нажимаем на кнопку, мы производим действие, но в ответ на это нажатие запускаются другие действия. Например, нажатие на значок принтера запускает печать документа на принтере и т.д.
Рассмотрим следующий пример:
public class EventsApp < public static void main(String[] args) < Button button = new Button(new ButtonClickHandler()); button.click(); button.click(); button.click(); >> class ButtonClickHandler implements EventHandler < public void execute()< System.out.println("Кнопка нажата!"); >> interface EventHandler < void execute(); >class Button < EventHandler handler; Button(EventHandler action)< this.handler=action; >public void click() < handler.execute(); >>
Итак, здесь у нас определен класс Button, который в конструкторе принимает объект интерфейса EventHandler и в методе click (имитация нажатия) вызывает метод execute этого объекта.
Далее определяется реализация EventHandler в виде класса ButtonClickHandler . И в основной программе объект этого класса передается в конструктор Button. Таким образом, через конструктор мы устанавливаем обработчик нажатия кнопки. И при каждом вызове метода button.click() будет вызываться этот обработчик.
В итоге программа выведет на консоль следующий результат:
Кнопка нажата! Кнопка нажата! Кнопка нажата!
Но казалось бы, зачем нам выносить все действия в интерфейс, его реализовать, почему бы не написать проще сразу в классе Button:
class Button < public void click()< System.out.println("Кнопка нажата!"); >>
Дело в том, что на момент определения класса нам не всегда бывают точно известны те действия, которые должны производиться. Особенно если класс Button и класс основной программы находятся в разных пакетах, библиотеках и могут проектироваться разными разработчиками. К тому же у нас может быть несколько кнопок — объектов Button и для каждого объекта надо определить свое действие. Например, изменим главный класс программы:
public class EventsApp < public static void main(String[] args) < Button tvButton = new Button(new EventHandler()< private boolean on = false; public void execute()< if(on) < System.out.println("Телевизор выключен.."); on=false; >else < System.out.println("Телевизор включен!"); on=true; >> >); Button printButton = new Button(new EventHandler() < public void execute()< System.out.println("Запущена печать на принтере. "); >>); tvButton.click(); printButton.click(); tvButton.click(); > >
Здесь у нас две кнопки — одна для включения-выключения телевизора, а другая для печати на принтере. Вместо того, чтобы создавать отдельные классы, реализующие интерфейс EventHandler, здесь обработчики задаются в виде анонимных объектов, которые реализуют интерфейс EventHandler. Причем обработчик кнопки телевизора хранит дополнительное состояние в виде логической переменной on .
В итоге консоль выведет нам следующий результат:
Телевизор включен! Запущена печать на принтере. Телевизор выключен..
И в завершении надо сказать, что интерфейсы в данном качестве особенно широко используются в различных графических API — AWT, Swing, JavaFX, где обработка событий объектов — элементов графического интерфейса особенно актуальна.
Pro Java
Механизм обратного вызова (callback) широко распространен в программировании. При обратном вызове программист задает действия, которые должны выполняться всякий раз, когда происходит некоторое событие. Например, можно задать действие, которое должно быть выполнено после щелчка на некоторой кнопке или при выборе определенного пункта меню.
Для примера, пакет javax.swing содержит класс Timer, который можно использовать для отсчета интервалов времени. Например, если в программе предусмотрены часы, то с помощью класса Timer можно отсчитывать каждую секунду и обновлять циферблат часов.
Устанавливая таймер, мы задаем интервал времени и указываем, что должно произойти по его истечении.
Как указать таймеру, что он должен делать? Во многих языках программирования задается имя функции, которую таймер должен периодически вызывать. Однако классы из стандартной библиотеки языка Java используют объектно-ориентированный подход. Программист должен передать таймеру объект некоторого класса. После этого таймер вызывает один из методов данного объекта. Передача объекта — более гибкий механизм, чем вызов функции, поскольку объект может нести дополнительную информацию.
Разумеется, таймер должен знать, какой метод он должен вызвать. Для этого таймеру нужно указать объект класса, реализующего интерфейс ActionListener из пакета java.awt.event. Этот интерфейс выглядит следующим образом:
public interface ActionListener extends EventListener public void actionPerformed ( ActionEvent e ) ;
>
По истечении заданного интервала времени таймер вызывает метод actionPerformed().
Предположим, нам нужно каждые две секунды выводить на экран сообщение о текущем времени. Для этого необходимо определить класс, реализующий интерфейс ActionListener, а затем поместить операторы, которые нужно выполнить, в тело метода actionPerformed().
Обратите внимание на параметр ActionEvent метода actionPerformed(). Он содержит информацию о событии, например, об объекте, его породившем. В нашей программе детальная информация о событии не важна, поэтому можно просто проигнорировать этот параметр.
Затем следует создать объект данного класса и передать его конструктору класса Timer.
![]()
Первый параметр конструктора Timer представляет собой интервал времени между точками отсчета, измеренный в миллисекундах. Сообщение должно выдаваться на экран каждые десять секунд. Второй параметр является объектом класса ActionListener.
t.start() запускает таймер и на экране каждые две секунды будет появляться сообщение о текущем времени.
После запуска таймера программа выводит на экран окно с сообщением и ждет, пока пользователь не щелкнет на кнопке OK, чтобы завершить работу.
Что такое callback-интерфейсы и с чем их едят?
Изучая интерфейсы, наткнулся на такую штуку,как callbak-интерфейс. Если я правильно понял,то это интерфейс-маячок,который можно прикрутить к чему-нибудь,что будет дергать этот интерфейс в случае каких-либо изменений(например такой интерфейс можно весить на канал связи и в случае прихода сообщений выполнять какое-то действие) и он в свою очередь будет выполнять прописанные методы. Вопрос в том как его реализовывать.Примеры из туториалов,которые я нашел в сети мне не совсем понятны. Объясните пожалуйста, как реализуется эта штука, или поделитесь ссылками на хорошие материалы по данной теме.
Отслеживать
34.4k 15 15 золотых знаков 65 65 серебряных знаков 94 94 бронзовых знака
задан 11 апр 2016 в 7:55
1,901 4 4 золотых знака 22 22 серебряных знака 38 38 бронзовых знаков
Для java эта тема широко освещена. Ещё есть Observer (наблюдатель). Ни одна книжка по java не обходится без Observer-а. Более древняя техника и наверное попроще. Без лишних объектов, прослоек. Прямо как вы хотите — интерфейс. А Listener предполагает передачу объекта-сообщения.
11 апр 2016 в 11:47
идея с Observer-ом мне понравилась,но Observer применяется наверное для масштабных проектов?к примеру у меня есть набор вебсокетных соединений. и есть одна точка,которая шлет сообщения в виде цифр. цифры собираются в коллекцию и расчитывается среднее значение,которое приходит клиентам на соккет. я хочу как-то фиксировать извмнение в коллекции,чтобы клиенты по ходу изменения коллекции получали измененное ср.значение коллекции,без обновления страницы. есть ли смысл реализовывать в таком случае этот паттерн?
12 апр 2016 в 7:59
Observer годится для всяких прожектов.
12 апр 2016 в 8:32
Тут вместо callback можно с очередью замутить. Поток, который читает из точки цифры, может вместо вызова callback, ставить цифры в очередь. Другой поток ждёт когда в этой очереди появляются цифры и рассылает дальше по сокетам.
12 апр 2016 в 8:40
можно,но в моем случае вебсоккетное соединение сделано на vert.x 3. там вебсоккет выступает и как поток чтения и как поток записи(и кидать туда еще потоки, я думаю не целесообразно),тем не менее я так и не врубился,как сделать то,что описал выше средствами данного фреймворка,потому дошел до listener’ов
12 апр 2016 в 9:11
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
callback — обратный вызов — понятие и применение очень широкое.
callback-и вроде вашего маячка называют listener-ами(слушателями по-нашему). Они регистрируются функцией регистрации и потом вызываются не понятно кем и не известно когда (наступит событие или нет? когда? кто знает. )
Есть и другие виды callback-ов.
Например в Win32 APIесть функция EnumWindows для перечисления открытых окошек. Она принимает в качестве параметра функцию обратного вызова EnumWindowsProc .
EnumWindows знает что вам нужны эти окошки, но не знает зачем. Кроме того по каким-то важным причинам она не хочет выдавать Вам сразу готовый список.
Но с помощью callback она сдаст всех по-одному. Для каждого обнаруженного окошка вызывается Ваша функция EnumWindowsProc , чтобы в ней Вы сами разобрались с этим окошком. И здесь функция callback если будет вызвана, то только во время работы EnumWindows , а не когда-нибудь потом.
Урок 13. Основы JAVA. Методы обратного вызова (callback)
Механизм обратного вызова(callbacks) широко распространен в программировании. При обратном вызове программист задает действия, которые должны выполняться всякий раз, когда происходит некоторое событие. И неважно, будете разрабатывать только java-программы или android-приложения – колбеки будут встречаться вам повсюду.
Для создания методов обратного вызова (callback) в java используются уже знакомые нам из прошлого урока интерфейсы.
Создадим новый класс SomeClass с интерфейсом Callback:
import javax.swing.*; public class SomeClass < // создаем колбек и его метод interface Callback< void callingBack(); >Callback callback; public void registerCallBack(Callback callback) < this.callback = callback; >void doSomething() < JOptionPane.showMessageDialog(null, "Выполняется работа"); // вызываем метод обратного вызова callback.callingBack(); >>
У интерфейса мы определили один метод callingBack(). Далее в классе мы создали объект интерфейса и инициализировали его в методе registerCallBack. В классе также был создан метод doSomething(), в котором может содержаться какой-то сложный код. Мы здесь создаем диалоговое окно, используя компонент JOptionPane библиотеки Swing. Кто не в курсе, Swing — библиотека для создания графического интерфейса программ на языке Java.
В конце работы метода doSomething() вызывается метод интерфейса callingBack() . В данном случае мы сами создали метод и знаем его код. Но во многих случаях, вы будете использовать готовый метод какого-то класса и можете даже не знать, что именно содержится в этом методе. Вам надо только знать, что такой метод существует и выполняет конкретную задачу.
Теперь нам нужен класс, реализующий интерфейс-callback. Создаем класс MyClass и подключаем интерфейс-колбек через ключевое слово implements. Среда разработки заставит нас реализовать шаблон метода интерфейса.
public class MyClass implements SomeClass.Callback < @Override public void callingBack() < System.out.println("Вызов метода обратного вызова"); >>
Теперь мы можем использовать метод обратного вызова callingBack () для решения своих задач. Будем здесь выводить текст в консоль. Создадим класс Main, в котором будет реализован метод main – точка входа в программу.
public class Main < public static void main(String[] args) < SomeClass someClass = new SomeClass(); MyClass myClass = new MyClass(); //инициализируем колбек, передавая методу registerCallBack экземпляр MyClass, реализующий интерфейс колбек someClass.registerCallBack(myClass); someClass.doSomething(); >>
Здесь создаем экземпляры классов, инициализируем колбек, передавая методу registerCallBack экземпляр MyClass, реализующий интерфейс-callback. И вызываем метод doSomething();
При старте программы будет выполняться код метода doSomething(); из класса SomeClass. На экране появилось диалоговое окно.

Когда мы нажмем кнопку, или закроем диалоговое окно, сработает метод обратного вызова callingBack(), который выведет сообщение в консоль.
Через интерфейс-callback также можно передавать какие-то данные. Давайте немного усложним пример.
package callback; import javax.swing.*; public class SomeClass < String replyTo; interface Callback< void callingBack(String s); >private Callback callback; public void registerCallBack(Callback callback) < this.callback = callback; >void doSomething() < int reply = JOptionPane.showConfirmDialog(null, "Вы программист?", "Опрос", JOptionPane.YES_NO_OPTION); if (reply == JOptionPane.NO_OPTION)< replyTo = "Нет"; >if (reply == JOptionPane.YES_OPTION) < replyTo = "Да"; >callback.callingBack(replyTo); > >
Объявим строковую переменную replyTo. Добавим аргумент метода callingBack – строковую переменную.
Изменим диалоговое окно – присвоим его новой целочисленной переменной reply, и изменим на showConfirmDialog, который имеет заголовок окна и больше одной кнопки ответа. В зависимости от нажатой кнопки переменной reply будет присвоено значение. Сравниваем ее значение с константой и присваиваем значение “Да” или “Нет” переменной replyTo.
Теперь внесем изменения в MyClass.
package callback; public class MyClass implements SomeClass.Callback < @Override public void callingBack(String s) < if (s != null) < System.out.println("Ваш ответ: " + s); >else < System.out.println("Вы не ответили на вопрос!"); >> >
Добавим аргумент в метод. И добавим условие проверки, что строка не пустая – это возможно, если вместо ответа просто закрыть диалоговое окно.
Класс Main без изменений.
package callback; public class Main < public static void main(String[] args) < SomeClass someClass = new SomeClass(); MyClass myClass = new MyClass(); someClass.registerCallBack(myClass); someClass.doSomething(); >>
Запускаем программу. Теперь текст сообщения в консоли меняется в зависимости от того, выберем мы да, нет или просто закроем окно.

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