java Java中的回调(代码解释)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4041522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Call backs in Java (code explanation)
提问by zengr
I came across this questionabout callbacks in Java. Hers is the running codeand original answer here.
我遇到了这个关于 Java 回调的问题。Hers 是此处的运行代码和原始答案。
- But I didn't understand how is it useful for callback?
- Can you explain the concept of callback to a Java programmer?
- 但我不明白它对回调有什么用?
- 你能向 Java 程序员解释回调的概念吗?
Code:
代码:
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));
}
}
采纳答案by madhurtanwani
I wrote a small blog post on this sometime back : http://madhurtanwani.blogspot.com/2010/09/callbacks-in-java.html. Hope it helps!
我曾经写过一篇关于此的小博文:http: //madhurtanwani.blogspot.com/2010/09/callbacks-in-java.html。希望能帮助到你!
Before I try explaining the above code post, I must say, its not the most intuitive or good use of call backs. The example I've used in my post is of Collections.sort() which clearly brings out the callbackpart.
在我尝试解释上面的代码帖子之前,我必须说,它不是回调的最直观或最好的用法。我在帖子中使用的示例是 Collections.sort() ,它清楚地显示了回调部分。
Neverthelss, for the code posted above, think of like this :
不过,对于上面贴出的代码,可以这样想:
- The main() function actually is a number (read Data) stream parsing algorithm, which will parse a pair of numbers (data sets) and then operate on them.
- Now, considering separation of concerns, the main() function should neither know or understand what operations can be performed on the datasets. In fact it should not even care of the data types of the data sets.
- However, since these data sets are specific to your domain, the main function should ideally delegatethe processing of the data to your domain specific classes.
- For it to do so, it must enforce a contract with the domain specific caller (the caller for main) and say - look, I'll call the
doJob
method on aVisitor
interface
implementations, whenever I receive a pair of data sets. What the caller must do is implement the Visitor interface and implement the domain specific logic to process the datasets.
- main()函数其实是一个数(读数据)流解析算法,会解析一对数(数据集),然后对其进行操作。
- 现在,考虑到关注点分离,main() 函数不应该知道或理解可以对数据集执行哪些操作。事实上,它甚至不应该关心数据集的数据类型。
- 但是,由于这些数据集特定于您的领域,因此理想情况下,主要功能应该将数据处理委托给您的领域特定类。
- 为此,它必须与特定于域的调用者(main 的调用者)签订合同并说 - 看,每当我收到一对数据集时,我都会
doJob
在Visitor
interface
实现上调用该方法。调用者必须做的是实现访问者接口并实现特定领域的逻辑来处理数据集。
The part of delegatingprocessing from the caller, back to the calleeis called a callbackimplemented using interface
(contract specification) in Java.
将调用者的处理委托回被调用者的部分称为在 Java 中使用(合同规范)实现的回调。interface
回答by Denilson Sá Maia
I don't want to start a flame war here... But the concept of callbacksis a lot easier to understand in languages like C/C++, JavaScript, Python, probably Ruby and many others. In such languages, a callback is just a function pointer. You pass your function as this function pointer, and the other code will call back your function using that pointer. As simple as that. (look at this C example from Wikipedia)
我不想在这里开始一场激烈的War……但是回调的概念在 C/C++、JavaScript、Python、可能还有 Ruby 和许多其他语言中更容易理解。在这些语言中,回调只是一个函数指针。您将您的函数作为此函数指针传递,其他代码将使用该指针回调您的函数。就如此容易。(看看维基百科中的这个 C 示例)
But Java does not have function pointers, and thus the Java programmer is required to use Anonymous Inner Classes, Interfacesand things like that in order to encapsulate a function inside a class, and pass an instance of that class as the callback.
但是 Java 没有函数指针,因此 Java 程序员需要使用匿名内部类、接口等类似的东西来将函数封装在类中,并将该类的实例作为回调传递。
I think I managed to answer your second question ("Can you explain the concept of callback to a Java programmer?"), but please see the other answers about how to implement that in Java.
我想我设法回答了你的第二个问题(“你能向 Java 程序员解释回调的概念吗?”),但请参阅有关如何在 Java 中实现它的其他答案。
回答by diegosasw
I used to develop in Java and I did not fully understand the callback concept until I began programming with C# and its delegates.
我曾经使用 Java 进行开发,直到我开始使用 C# 及其委托进行编程时,我才完全理解回调概念。
The reason of that is because as @Denilson Sá perfectly mentioned Java does not use pointers to functions. In other words, in Java you can call a method and pass some arguments such as primitive values (int, long, char, boolean, etc.) and objects (String or any instance of any class as when you passs an object you are basically passing the address in memory of the real object that lives somewhere in memory).
这样做的原因是因为@Denilson Sá 完美地提到了 Java 不使用指向函数的指针。换句话说,在 Java 中,您可以调用一个方法并传递一些参数,例如原始值(int、long、char、boolean 等)和对象(字符串或任何类的任何实例,当您传递对象时,您基本上是传递位于内存中某处的真实对象的内存地址)。
The callback concept in Java could be implemented by using interfaces and passing them (the object that implements them) as arguments. Imagine you have the following interface that defines 2 methods that ANY class that wants to behave as a ResultListener must implement.
Java 中的回调概念可以通过使用接口并将它们(实现它们的对象)作为参数传递来实现。想象一下,您有以下接口定义了 2 个方法,任何想要作为 ResultListener 的类都必须实现这些方法。
interface ResultListener {
void onSuccessOperation(String description);
void onFailedOperation(String description);
}
Now imagine you have a main program that is running inside the showScreenmethod
现在假设您有一个在showScreen方法中运行的主程序
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);
}
}
And this is the SmartClass that knows how to divide.
这就是知道如何划分的 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);
}
}
}
The interesting part here is that MyMainScreen is behaving as a ResultListener so it needs to implement the methods defined in the interface ResultListener. MyMainScreen knows how to print messages on console, but it does not know anything about calculations, and that is why it instantiates the SmartClass to use its method divideAndNotify that accepts 2 numbers and a reference to the instance that will listen to the result (in our case this instance is the MyMainScreen instance itself, and that's why it passes itself with the word this)
这里有趣的部分是 MyMainScreen 表现为一个 ResultListener,因此它需要实现接口 ResultListener 中定义的方法。MyMainScreen 知道如何在控制台上打印消息,但它对计算一无所知,这就是为什么它实例化 SmartClass 以使用其方法 DivisionAndNotify 接受 2 个数字和对将侦听结果的实例的引用(在我们的如果此实例是 MyMainScreen 实例本身,这就是为什么它通过单词this传递自己)
The SmartClass method divideAndNotify knows maths and will notify whoever is listening with the result of the operation. Its method knows that resultListener will contain the reference to an object that knows what to do when the result is successful or unsuccessful.
SmartClass 方法divideAndNotify 了解数学,并将用运算结果通知正在监听的任何人。它的方法知道 resultListener 将包含对一个对象的引用,该对象知道在结果成功或不成功时该做什么。
The callback concept here is that SmartClass is delegating the functionality on what to do with the result, it is like "calling back" something in the instance that it received as a parameter.
这里的回调概念是 SmartClass 委托功能来处理结果,就像“回调”它作为参数接收的实例中的某些东西。
As a summary: A callbackis simply a DELEGATION of a task.
总结:回调只是一个任务的委托。
PS: With C# this concept is much more straightforward because C# has delegate types that are variables that store addresses of memory where functions reside (the functions that store must match the signature defined in the delegate).
PS:在 C# 中,这个概念要简单得多,因为 C# 具有委托类型,这些类型是存储函数所在内存地址的变量(存储的函数必须与委托中定义的签名匹配)。
回答by iggymoran
They are called "Anonymous Inner Classes". They are basically an implementation of an interface/abstract class without having to write a fully blown class.
它们被称为“匿名内部类”。它们基本上是接口/抽象类的实现,而无需编写完整的类。
The compiler will actually create a class for each one of these, so if you compile the above code, you'll see something like:
编译器实际上会为每一个创建一个类,所以如果你编译上面的代码,你会看到类似的东西:
Main.class
Main$Visitor.class
Main.class <-- This is probably the "adder" implementation
Main.class <-- This is probably the "multiplier" implementation
The beauty of these classes is that they can read stuff from your method/class without you having to pass those parameters. For instance:
这些类的美妙之处在于它们可以从您的方法/类中读取内容,而无需您传递这些参数。例如:
...
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;
}
};
...
They are particularly useful for event handling (think Swing), where you usually need to implement the ActionListener interface where you need to have a actionPerormed() method. If you have a UI class with many different controls, whenever you register the listeners, you might want to register these annonymous classes to: a) make the code (arguably) more readable and b) to make it easier to know what each component does, instead of having a giant "if-else if-else" style actionPerfomed implementation
它们对于事件处理(想想 Swing)特别有用,在这种情况下,您通常需要实现 ActionListener 接口,并且需要有 actionPerormed() 方法。如果您有一个包含许多不同控件的 UI 类,那么每当您注册侦听器时,您可能希望注册这些匿名类以:a) 使代码(可以说)更具可读性 b) 更容易了解每个组件的作用, 而不是有一个巨大的“if-else if-else”风格的 actionPerfomed 实现
for instance:
例如:
//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
});
回答by Alex Nikolaenkov
You're talking about an entity I never called callbacks myself. The entities your are talking about are called function pointers (as mentioned by madhuranwani) / delegates / anonymous functions / actions.
你在谈论一个我自己从未称之为回调的实体。您所谈论的实体称为函数指针(如 madhuranwani 所述)/委托/匿名函数/动作。
These ones are usually used for customization of generic algorithm implementations (such as Collections.sort, as you mentioned).
这些通常用于定制通用算法实现(如您提到的 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();
}
Entity which are usually called callbacks in my area act more like listeners. Here is an example:
在我的领域通常被称为回调的实体更像是监听器。下面是一个例子:
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();
}