Обратные вызовы в Java (объяснение кода) - PullRequest
5 голосов
/ 28 октября 2010

Я сталкивался с этим вопросом о обратных вызовах в Java.Ее набирает код и оригинальный ответ здесь .

  1. Но я не понял, как это полезно для обратного вызова?
  2. Можете ли вы объяснить концепцию обратного вызова программисту на Java?

Код:

public class Main {

    public interface Visitor {
        int DoJob(int a, int b);
    }


    public static void main(String[] args) {
        Visitor adder = new Visitor(){
            public int DoJob(int a, int b) {
                return a + b;
            }
        };

        Visitor multiplier = new Visitor(){
            public int DoJob(int a, int b) {
                return a*b;
            }
        };

        System.out.println(adder.DoJob(10, 20));
        System.out.println(multiplier.DoJob(10, 20));

    }
}

Ответы [ 5 ]

6 голосов
/ 28 октября 2010

Я написал небольшое сообщение в блоге об этом некоторое время назад: http://madhurtanwani.blogspot.com/2010/09/callbacks-in-java.html. Надеюсь, это поможет!

Прежде чем я попытаюсь объяснить вышеупомянутый код, я должен сказать, что это не самый интуитивный или хорошийиспользование обратных вызовов.Пример, который я использовал в своем посте, относится к Collections.sort (), который явно выдает callback part.

Тем не менее, для кода, размещенного выше, подумайте так:

  1. Функция main () на самом деле представляет собой алгоритм синтаксического анализа потока чисел (чтение данных), который будет анализировать пару чисел (наборов данных) и затем работать с ними.
  2. Теперь,Учитывая разделение интересов, функция main () не должна ни знать, ни понимать, какие операции можно выполнять с наборами данных.На самом деле это даже не должно заботиться о типах данных наборов данных.
  3. Однако, поскольку эти наборы данных являются специфическими для вашего домена, в идеале основная функция в идеале должна делегировать обработкуданные в классы, специфичные для вашего домена.
  4. Для этого он должен принудительно заключить договор с вызывающим абонентом домена (вызывающим абонентом для main) и сказать - смотрите, я вызову метод doJob дляVisitor interface реализации, когда я получаю пару наборов данных.Вызывающий объект должен реализовать интерфейс Visitor и реализовать специфичную для домена логику для обработки наборов данных.

Часть , делегирующая обработку от вызывающего возвращение к вызываемому называется обратным вызовом , реализованным с использованием interface (спецификация контракта) в Java.

4 голосов
/ 28 октября 2010

Я не хочу начинать огненную войну здесь ... Но концепция обратных вызовов намного проще понять в таких языках, как C / C ++, JavaScript, Python, возможно, Ruby и многих других.,В таких языках обратный вызов - это просто указатель на функцию .Вы передаете свою функцию как этот указатель на функцию, а другой код будет вызывать вашу функцию с помощью этого указателя.Так просто.( посмотрите на этот пример C из Википедии )

Но Java не имеет указателей на функции, и поэтому программисту Java необходимо использовать Анонимные внутренние классы , Интерфейсы и тому подобное, чтобы инкапсулировать функцию внутри класса и передать экземпляр этого класса в качестве обратного вызова.

Я думаю, что мне удалось ответить на ваш второй вопрос ( "Можете ли вы объяснить концепцию обратного вызова программисту на Java? "), но, пожалуйста, посмотрите другие ответы о том, как реализовать это в Java.

3 голосов
/ 06 августа 2014

Раньше я занимался разработкой на Java и не до конца понимал концепцию обратного вызова, пока не начал программировать на C # и его делегатах.

Причина этого в том, что, как @Denilson Sá прекрасно упомянул, Java не использует Javaуказатели на функции.Другими словами, в Java вы можете вызывать метод и передавать некоторые аргументы, такие как примитивные значения (int, long, char, boolean и т. Д.) И объекты (String или любой экземпляр любого класса, например, когда вы передаете объект, вы в основномпередача адреса в память реального объекта, который живет где-то в памяти).

Концепция обратного вызова в Java может быть реализована с использованием интерфейсов и передачи их (объект, который их реализует) в качестве аргументов.Представьте, что у вас есть следующий интерфейс, который определяет 2 метода, которые ЛЮБОЙ класс, который хочет вести себя как ResultListener, должен реализовать.

interface ResultListener {
   void onSuccessOperation(String description);
   void onFailedOperation(String description);
}

Теперь представьте, что у вас есть основная программа, которая работает внутри showScreen method

class MyMainScreen implements ResultListener {
   public void showScreen() {
    //do some things..
    SmartClass smartClass = new SmartClass();
    smartClass.divideAndNotify(5, 0, this);
    }

    public void onSuccessOperation(String description) {
       System.out.println("SUCCESS!!. " + description);
    }

    public void onFailedOperation(String description) {
       System.out.println("FAILED. " + description);
    }
}

И это SmartClass, который знает, как делить.

class SmartClass {
   public void divideAndNotify(int numerador, int denominador, ResultListener resultListener) {
        if (denominador == 0) {
            resultListener.onFailedOperation("Nobody can divide by zero!!");
        } else {
            int total = numerador / denominador;
            resultListener.onSuccessOperation("The result is " + total);
        }
    }
}    

Интересно, что MyMainScreen ведет себя как ResultListener, поэтому ему нужно реализовать методыопределяется в интерфейсе ResultListener.MyMainScreen знает, как печатать сообщения на консоли, но он ничего не знает о вычислениях, и именно поэтому он создает экземпляр SmartClass, чтобы использовать его методdivAndNotify, который принимает 2 числа и ссылку на экземпляр, который будет прослушивать результат (в нашемв данном случае этот экземпляр является самим экземпляром MyMainScreen, и поэтому он передает себя со словом this )

Метод SmartClassdivAndNotify знает математику и уведомляет любого, кто слушает, о результате операции.,Его метод знает, что resultListener будет содержать ссылку на объект, который знает, что делать, если результат успешен или неуспешен.

Концепция обратного вызова здесь заключается в том, что SmartClass делегирует функциональность того, что делать с результатом,это похоже на «обратный вызов» чего-либо в экземпляре, который он получил в качестве параметра.

Как итог: обратный вызов - это просто ДЕЛЕГАЦИЯ задачи.

PS: С C # эта концепция намного проще, потому что C # имеет типы делегатов, которые являются переменными, которые хранят адреса памяти, где находятся функции (функции, которые хранят, должны соответствовать сигнатуре, определенной в делегате).

1 голос
/ 28 октября 2010

Они называются "Анонимные внутренние классы". По сути, они являются реализацией интерфейса / абстрактного класса без необходимости написания полноценного класса.

Компилятор фактически создаст класс для каждого из них, поэтому, если вы скомпилируете приведенный выше код, вы увидите что-то вроде:

Main.class
Main$Visitor.class
Main$1.class  <-- This is probably the "adder" implementation
Main$2.class  <-- This is probably the "multiplier" implementation

Прелесть этих классов в том, что они могут читать вещи из вашего метода / класса без необходимости передавать эти параметры. Например:

...
final int extraMultiplyer = 10;

Visitor multiplier = new Visitor(){
    public int DoJob(int a, int b) {
        //Note that extraMultiplyer is defined in the main() method
        //and is final.
        return a*b*extraMultiplyer;
    }
};
...

Они особенно полезны для обработки событий (например, Swing), где вам обычно нужно реализовать интерфейс ActionListener, где вам нужен метод actionPerormed (). Если у вас есть класс пользовательского интерфейса с множеством различных элементов управления, всякий раз, когда вы регистрируете слушателей, вы можете зарегистрировать эти анонимные классы, чтобы: а) сделать код (возможно) более читабельным и б) чтобы было проще узнать, что делает каждый компонент вместо того, чтобы иметь гигантскую реализацию actionPerfomed в стиле if-else if-else

например:

//abbreviated code
button1.addActionListener(new ActionListener(){
    //you do what you need here for the action of pressing this button
});
button2.addActionListener(new ActionListener() {
   //you do what you need here for the action of pressing this button
});
0 голосов
/ 28 октября 2010

Вы говорите о сущности, которую я никогда не называл обратными вызовами.Объекты, о которых вы говорите, называются указателями на функции (как упомянуто madhuranwani) / делегаты / анонимные функции / действия.

Эти обычно используются для настройки реализации универсального алгоритма (такого как Collections.sort, как вы упомянули).

    public class Actions {
    public static void main(String[] args) {
        printingAlgorithm(new Action() {

            public void perform() {
                System.out.println("CustomAction.perform");
            }
        });
    }

    private static void printingAlgorithm(Action customization) {
        System.out.println("------");
        customization.perform();
        System.out.println("++++++");
    }
}

interface Action {
    void perform();
}

Объект, который обычно называется обратным вызовом в моей области, действует больше какслушатели.Вот пример:

public class Callbacks {

    public static void main(String[] args) {
        printingAlgorithm(new PrintingCallback() {
            public void printBody() {
                System.out.println("custom body");
            }

            public void printHeader() {
                System.out.println("---------");
            }

            public void printFooter() {
                System.out.println("+++++++++");
            }
        });
    }

    private static void printingAlgorithm(PrintingCallback callback) {
        callback.printHeader();
        callback.printBody();
        callback.printFooter();
    }
}

interface PrintingCallback {
    void printHeader();

    void printBody();

    void printFooter();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...