我遇到了关于Java回调的question。 Hers是正在运行的code和原始答案here。
代码:
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));
}
}
答案 0 :(得分:6)
我曾在这篇文章中写过一篇小博文:http://madhurtanwani.blogspot.com/2010/09/callbacks-in-java.html。希望它有所帮助!
在我尝试解释上面的代码之前,我必须说,它不是最直观或最好的回调。我在帖子中使用的示例是Collections.sort(),它清楚地显示了回调部分。
Neverthelss,对于上面发布的代码,想到这样:
doJob
上Visitor
{ 1}}实现,每当我收到一对数据集。调用者必须做的是实现Visitor接口并实现特定于域的逻辑来处理数据集。 委派处理从来电回到被叫的部分称为回调,使用 Java中的interface
(合同规范)。
答案 1 :(得分:4)
我不想在这里开始一场火焰战争...但是回调的概念在C / C ++,JavaScript,Python,可能是Ruby等许多语言中更容易理解其他。在这些语言中,回调只是一个函数指针。您将函数作为此函数指针传递,其他代码将使用该指针回调函数。就如此容易。 (look at this C example from Wikipedia)
但Java没有函数指针,因此Java程序员需要使用匿名内部类,接口等类似的东西来封装一个函数一个类,并将该类的实例作为回调传递。
我想我已经设法回答了你的第二个问题(“你能解释回调给Java程序员的概念吗?”),但请参阅其他答案,了解如何在Java中实现它。
答案 2 :(得分:3)
我曾经用Java开发过,直到我开始使用C#及其代表进行编程之前,我还没有完全理解回调概念。
原因是因为@DenilsonSá完全提到Java不使用函数指针。 换句话说,在Java中你可以调用一个方法并传递一些参数,比如原始值(int,long,char,boolean等)和对象(String或任何类的任何实例,就像你传递一个对象一样,你基本上将内存中的地址传递给存在于内存中的真实对象。)
Java中的回调概念可以通过使用接口并将它们(实现它们的对象)作为参数传递来实现。假设您有以下接口,该接口定义了两个希望表现为ResultListener的类必须实现的方法。
interface ResultListener {
void onSuccessOperation(String description);
void onFailedOperation(String description);
}
现在假设你有一个在 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);
}
}
这就是知道如何划分的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以使用它接受2个数字的方法divideAndNotify以及对将监听结果的实例的引用(在我们的case这个实例是MyMainScreen实例本身,这就是为什么它传递自己的单词 this )
SmartClass方法divideAndNotify知道数学,并将通知操作结果的任何人。它的方法知道resultListener将包含对一个对象的引用,该对象知道在结果成功或不成功时该怎么做。
这里的回调概念是SmartClass委派关于如何处理结果的功能,就像在实例中“回调”它作为参数接收的东西。
总结:回调只是一个任务的代表。
PS:使用C#这个概念要简单得多,因为C#有委托类型,这些变量存储函数所在的内存地址(存储的函数必须与委托中定义的签名相匹配)。答案 3 :(得分:1)
他们被称为“匿名内部类”。它们基本上是接口/抽象类的实现,而不必编写完全成熟的类。
编译器实际上会为每一个创建一个类,所以如果你编译上面的代码,你会看到类似的东西:
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()方法。 如果你有一个包含许多不同控件的UI类,那么每当你注册监听器时,你可能希望将这些匿名类注册到:a)使代码(可以说)更具可读性; b)让每个组件更容易知道而不是有一个巨大的“if-else if-else”风格actionPerfomed实现
例如:
//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
});
答案 4 :(得分:0)
你说的是我自己从未称之为回调的实体。您正在谈论的实体称为函数指针(如madhuranwani所述)/ delegates / anonymous functions / actions。
这些通常用于定制通用算法实现(例如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();
}