Java 中的函数指针

这可能是一些常见和琐碎的事情,但我似乎很难找到一个具体的答案。在 C # 中有一个委托的概念,这个概念与 C + + 中函数指针的概念密切相关。Java 中有类似的功能吗?鉴于指针在某种程度上是缺失的,那么解决这个问题的最佳方法是什么?先说清楚,我们说的可是头等舱。

178901 次浏览

不,函数不是 Java 中的第一类对象。你可以通过实现一个处理程序类来做同样的事情——这就是 Swing 中回调的实现方式。

然而,在未来版本的 java-Javaworld中有一些关于闭包的建议(这是您正在讨论的正式名称) ,其中有一篇有趣的文章。

你可以用接口代替函数指针。假设您想运行一个集合并对每个元素执行某些操作。

public interface IFunction {
public void execute(Object o);
}

这是我们可以传递给 CollectionUtils2.doFunc (Collection c,IFunction f)的接口。

public static void doFunc(Collection c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}

举个例子,我们有一个数字集合,你想把1加到每个元素上。

CollectionUtils2.doFunc(List numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
}
});

类函数指针功能的 Java 习惯用法是一个实现接口的匿名类,例如。

Collections.sort(list, new Comparator<MyClass>(){
public int compare(MyClass a, MyClass b)
{
// compare objects
}
});

更新: 以上内容在 Java 8之前的 Java 版本中是必需的。现在我们有了更好的选择,即 lambdas:

list.sort((a, b) -> a.isGreaterThan(b));

参考方法:

list.sort(MyClass::isGreaterThan);

Java 里没有这种东西。您需要将函数封装到某个对象中,并将引用传递给该对象,以便将引用传递给该对象上的方法。

在语法上,可以通过使用定义为就地的匿名类或定义为类的成员变量的匿名类来在一定程度上缓解这个问题。

例如:

class MyComponent extends JPanel {
private JButton button;
public MyComponent() {
button = new JButton("click me");
button.addActionListener(buttonAction);
add(button);
}


private ActionListener buttonAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// handle the event...
// note how the handler instance can access
// members of the surrounding class
button.setText("you clicked me");
}
}
}

要实现类似的功能,可以使用匿名内部类。

如果要定义接口 Foo:

interface Foo {
Object myFunc(Object arg);
}

创建一个方法 bar,它将接收一个“函数指针”作为参数:

public void bar(Foo foo) {
// .....
Object object = foo.myFunc(argValue);
// .....
}

最后按如下方式调用该方法:

bar(new Foo() {
public Object myFunc(Object arg) {
// Function code.
}
}

这让我想起了史蒂夫 · 叶格的 名词王国中的死刑。它基本上声明 Java 需要对每个操作都有一个对象,因此没有“只有动词”的实体,比如函数指针。

检查闭包是如何在 lambdaj 库中实现的。它们实际上有一种非常类似于 C # 委托的行为:

Http://code.google.com/p/lambdaj/wiki/closures

我使用反射在 Java 中实现了回调/委托支持。

它是如何工作的

我们有一个名为 Callback 的原则类和一个名为 WithParms 的嵌套类。需要回调的 API 将采用 Callback 对象作为参数,如果需要,则创建 Callback。WithParms 作为方法变量。由于这个对象的许多应用程序都是递归的,所以这个工作非常干净。

由于性能对我来说仍然是高优先级的,我不想被要求创建一个一次性对象数组来保存每次调用的参数——毕竟在一个大型数据结构中可能有成千上万个元素,而在一个消息处理场景中,我们可能最终在一秒钟内处理成千上万个数据结构。

为了线程安全,参数数组需要为 API 方法的每次调用唯一地存在,为了效率,每次调用回调都应该使用相同的参数数组; 我需要第二个对象,这个对象的创建成本很低,以便将回调与参数数组绑定用于调用。但是,在某些场景中,由于其他原因,调用程序可能已经有了参数数组。由于这两个原因,参数数组不属于 Callback 对象。另外,调用的选择(将参数作为数组或单个对象传递)属于使用回调的 API,使其能够使用最适合其内部工作的调用。

WithParms 嵌套类是可选的,有两个用途,它包含回调调用所需的参数对象数组,并且它提供10个重载调用()方法(从1到10个参数) ,这些方法加载参数数组,然后调用回调目标。

你可以使用反射来做到这一点。

作为参数传递对象和方法名(作为字符串) ,然后调用方法。例如:

Object methodCaller(Object theObject, String methodName) {
return theObject.getClass().getMethod(methodName).invoke(theObject);
// Catch the exceptions
}

然后把它用在:

String theDescription = methodCaller(object1, "toString");
Class theClass = methodCaller(object2, "getClass");

当然,检查所有异常并添加所需的强制转换。

相对于这里的大多数人来说,我对 java 还是个新手,但是因为我还没有看到类似的建议,所以我有另外一个建议。我不确定这是不是一个好的做法,甚至建议之前,我只是没有得到它。我只是喜欢它,因为我认为它的自我描述。

 /*Just to merge functions in a common name*/
public class CustomFunction{
public CustomFunction(){}
}


/*Actual functions*/
public class Function1 extends CustomFunction{
public Function1(){}
public void execute(){...something here...}
}


public class Function2 extends CustomFunction{
public Function2(){}
public void execute(){...something here...}
}


.....
/*in Main class*/
CustomFunction functionpointer = null;

然后根据应用程序,分配

 functionpointer = new Function1();
functionpointer = new Function2();

等等。

顺便拜访一下

 functionpointer.execute();

Java8引入了 lambdas 和 方法参考文献。因此,如果您的函数匹配 功能界面(您可以创建自己的) ,您可以在这种情况下使用方法引用。

Java 提供了一组 通用功能接口:

public class Test {
public void test1(Integer i) {}
public void test2(Integer i) {}
public void consumer(Consumer<Integer> a) {
a.accept(10);
}
public void provideConsumer() {
consumer(this::test1);   // method reference
consumer(x -> test2(x)); // lambda
}
}