Java中的函数指针

这可能是一些常见和微不足道的事情,但我似乎无法find具体的答案。 在C#中有一个委托的概念,强烈地涉及到来自C ++的函数指针的思想。 Java中是否有类似的function? 鉴于指针是有点缺席,这是最好的方法是什么? 而要清楚的是,我们在这里讲第一课。

类似于函数指针function的Java成语是一个实现接口的匿名类,例如

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

更新:在Java 8之前的Java版本中,上述是必需的。现在我们有更好的select,即lambda:

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

和方法参考:

 list.sort(MyClass::isGreaterThan); 

你可以用一个接口取代一个函数指针。 比方说,你想通过一个集合运行,并与每个元素做一些事情。

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

这是我们可以传递给一些说CollectionUtils2.doFunc(集合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++; } }); 

你可以使用reflection来做到这一点。
作为parameter passing对象和方法名称(作为string),然后调用该方法。 例如:

 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"); 

当然,检查所有exception并添加所需的强制转换。
对不起,我的英文不好。
再见!

不,函数不是java中的头等对象。 你可以通过实现一个处理器类来做同样的事情 – 这就是在Swing中如何实现callback。

然而,在未来的Java版本中有closures的build议(你正在谈论的正式名称) – Javaworld有一篇有趣的文章。

这让人想起史蒂夫·叶格的“名词王国的执行” 。 它基本上规定Java需要每个动作的对象,因此不具有像动词指针这样的“只动”实体。

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

如果你要定义一个接口Foo

 interface Foo { Object myFunc(Object arg); } 

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

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

最后调用方法如下:

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

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

在语法上,这可以通过使用定义在位的匿名类或定义为类的成员variables的匿名类来在一定程度上得到缓解。

例:

 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"); } } } 

我已经使用reflection在Java中实现了callback/委托支持。 细节和工作来源可以在我的网站上find 。

怎么运行的

我们有一个名为Callback的原型类,它带有一个名为WithParms的嵌套类。 需要callback的API将一个Callback对象作为参数,如果需要的话,创build一个Callback.WithParms作为方法variables。 由于这个对象的很多应用都是recursion的,所以这个工作非常干净。

性能仍然是我的首要任务,我不希望被要求创build一个一次性的对象数组来保存每个调用的参数 – 毕竟在一个大型的数据结构中可能有成千上万的元素,并在一个消息处理我们最终可能会每秒处理数千个数据结构。

为了成为线程安全的参数数组需要唯一地存在于API方法的每个调用中,并且为了效率,每次调用callback都应该使用同一个参数; 我需要第二个对象,这将创build便宜,以便绑定与调用参数数组的callback。 但是,在某些情况下,由于其他原因,调用者将已经拥有参数数组。 由于这两个原因,参数数组不属于callback对象。 同样,select调用(将参数作为数组或单独对象传递)属于API的手中,使用callback使它能够使用最适合其内部工作的调用。

WithParms嵌套类是可选的,它有两个目的,它包含callback调用所需的参数对象数组,它提供了10个重载的invoke()方法(有1到10个参数),它们加载参数数组,然后调用callback目标。

Java8引入了lambdas和方法引用 。 所以如果你的函数匹配一个函数接口 (你可以创build你自己的),你可以在这种情况下使用方法引用。

Java提供了一组通用的function接口 。 而您可以执行以下操作:

 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 } } 

检查closures是如何在lambdaj库中实现的。 他们实际上有一个非常类似于C#代表的行为:

http://code.google.com/p/lambdaj/wiki/Closures

相对于大多数人来说,我是新来的Java,但因为我没有看到类似的build议,我有另一种selectbuild议。 林不知道是否是一个好的做法,甚至以前build议,我只是没有得到它。 我只是喜欢它,因为我认为它的自我描述。

  /*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();