Java中的函数指针

Ben*_*key 147 java delegates pointers function-pointers

这可能是常见和微不足道的事情,但我似乎无法找到具体的答案.在C#中有一个委托的概念,它与C++中的函数指针的思想密切相关.Java中是否有类似的功能?鉴于指针有点缺席,最好的方法是什么?要说清楚,我们在这里谈论头等舱.

Mic*_*rdt 125

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

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

更新:在Java 8之前的Java版本中,上述内容是必需的.现在我们有更好的替代方案,即lambdas:

list.sort((a, b) -> a.isGreaterThan(b));
Run Code Online (Sandbox Code Playgroud)

和方法参考:

list.sort(MyClass::isGreaterThan);
Run Code Online (Sandbox Code Playgroud)

  • @Raedwald C++有仿函数,C++ 0x有封闭和lambdas构建在仿函数之上.它甚至还有`std :: bind`,它将参数绑定到函数并返回一个可调用对象.我无法在这些方面为C辩护,但C++确实比Java更好. (73认同)
  • 是的,我实际上会在任何一天将CR函数指针放在crufty包装器类上 (21认同)
  • @zneak,@ Raedwald:您可以通过传递指向用户数据的指针(例如:struct)在C中执行此操作.(并且可以用每个新级别的回调间接来封装它)它实际上相当干净. (19认同)
  • Java 8有更好的语法. (3认同)
  • 策略设计模式。当您希望函数使用一些未提供给函数参数的非全局数据时,它不像C或C ++函数指针那样丑陋。 (2认同)
  • @Raedwald,这就是C#中的代表的作用!它们是干净的,类型安全的函数指针。 (2认同)

rau*_*ach 64

您可以使用接口替换函数指针.假设你想要运行一个集合并对每个元素做一些事情.

public interface IFunction {
  public void execute(Object o);
}
Run Code Online (Sandbox Code Playgroud)

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

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

举个例子说我们有一个数字集合,你想为每个元素添加1.

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


小智 41

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

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

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

然后使用它,如:

String theDescription = methodCaller(object1, "toString");
Class theClass = methodCaller(object2, "getClass");
Run Code Online (Sandbox Code Playgroud)

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

  • 这是1.丑陋和慢.但仍然是一个有效的答案.;) (14认同)
  • 除了"我如何编写慢速狡猾的Java代码"之外,反射并不是正确的答案:D (7认同)
  • 它可能是"丑陋"而且速度慢,但我相信反射允许做出接受的答案中基于接口的解决方案无法做到的事情(除非我弄错了),即在同一代码中调用同一对象的各种方法一部分. (4认同)

jwo*_*ard 20

不,函数不是java中的第一类对象.你可以通过实现一个处理程序类来做同样的事情 - 这就是在Swing等中实现回调的方法.

然而,在未来的Java版本中,有关于闭包的建议(你正在谈论的官方名称) - Javaworld有一篇有趣的文章.


Yuv*_*l F 15

这让人想起Steve Yegge 在名词王国执行.它基本上表明Java需要每个动作的对象,因此没有像函数指针那样的"仅动词"实体.


Kin*_*ick 8

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

如果要定义接口Foo:

interface Foo {
    Object myFunc(Object arg);
}
Run Code Online (Sandbox Code Playgroud)

创建一个bar接收"函数指针"作为参数的方法:

public void bar(Foo foo) {
    // .....
    Object object = foo.myFunc(argValue);
    // .....
}
Run Code Online (Sandbox Code Playgroud)

最后调用方法如下:

bar(new Foo() {
    public Object myFunc(Object arg) {
        // Function code.
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 6

Java8引入了lambda和方法引用.因此,如果您的函数与功能界面匹配(您可以创建自己的界面),则可以在这种情况下使用方法引用.

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
   }
}
Run Code Online (Sandbox Code Playgroud)


Voi*_*ter 5

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)