C++11:Class 将函数指针(模板化的非成员函数)存储到 Java

C++11: Class storing a function pointer (templatized, non-member function) to Java

我主要不是 Java 程序员...我想找到相应的 Java 语法 class 将函数指针(模板化)存储为变量。函数指针指向一个函数"outside"class。原始代码在 C++11 中:

#include <memory>

template <typename T>
using p_function = T(*)(T, T, T);

template <typename T>
class A
{
   private:
      int k;
      p_function<T> pf;
   public:
      A() { pf = NULL; k = 0; }
      A(p_function<T> pf_, int k_) { pf = pf_; k = k_; }
      T getF(const T a1, const T a2, const T a3) const { return pf(a1, a2, a3); }
};

template <typename T>
T f1(T x, T y, T z) { return x + y + z; }

template <typename T>
T f2(T x, T y, T z) { return x - y - z; }

int main()
{
    A<double> aa (f1<double>, 1.0);
    double val= aa.getF(1.0, 2.0, 3.0);
}

思考问题,接口的使用是否合理?

 public interface Function <T> {
    T pf(T x, T y, T z);
 }

或者,有没有更好的办法? Java发展较快,可能比几年前有"straighter"建设。有几个我无法加入的要求。我可以在 Java 中索取简短的代码示例吗?非常感谢您的帮助。

我不确定我是否正确回答了您的问题,但请查看 this Whosebug post

在java中有几个关于如何实现函数指针的答案。

编辑

我的 C++ 经验不足,无法提供代码示例。

编辑 2

根据我上面提到的post,你可以尝试这样的事情:

public class WithFunction {

//Empty constructor, can be left out
public WithFunction () {...}

//The function you want to reference
public int myReferencedFunction () {...}
}

然后

public class MethodCaller {
  public static Object call (Object theObject, String methodName) {
    return theObject.getClass().getMethod(methodName).invoke(theObject);
    //catch Exceptions
  }
}

那你就可以了

public static void main (String [] args) {
  WithFunction obj1 = new WithFunction();
  Object result = MethodCaller.call (obj1, "toString");
  int result = (int) MethodCaller.call (obj1, "myReferencedFunction");
}

通知:

你需要捕获很多异常。需要强大的错误处理能力..

如果你使用一个接口,你也可以多次实现它,应该有你需要的自由度

使用 java 8. 使用 "functional" 接口(实际上),其中接口仅定义一个函数。

为了不过度使用现有的功能 class,引入你自己的名字。

@FunctionalInterface
public interface TriFunction<T> {
    T apply(T x, T y, T z);
}

用 FunctionalInterface 注释标记它是一种防止添加第二个函数等的做法。

class Foo {
    public static Bar hop(Bar x, Bar y, Bar z) { ... }
}

TriFunction<Bar> pf = Foo::hop;
TriFunction<Integer> pg = (x, y, z) -> x + y + z;
Bar bara = pf.apply(a, b, c);

对于原始类型,最好定义自己的接口而无需泛型参数类型。以上 pg 需要 3 次将包装器对象拆箱,并再次将其装箱到一个对象。

java.util.function 包含许多功能接口,例如 BinaryOperatorIntBinaryOperator

在Java8中,可以使用方法引用。此处有更多信息:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

基本上,Java 8 为接口提供了一种特殊的方法 属性,它们可以(有点)像函数指针一样使用。您可以将 lambda 或方法引用分配给此类类型的对象。

例如,与您的问题有些相关:

public class HelloWorld {

    public interface Function <T> {
        T op(T x, T y);
    }

    public static class Functions {
        static int add(int x, int y) { return x + y; }
        static int sub(int x, int y) { return x - y; }
    }

    static Function<Integer> f1, f2; // <-- "function pointer"

    public static void main(String []args) {
        f1 = Functions::add; // <-- static method reference
        f2 = Functions::sub; // <-- static method reference

        System.out.println("Test: " + f1.op(1,2) + ", " + f2.op(1,2));
    }

}

如您所料,此代码打印出来:

Test: 3, -1

所以你的问题的这一部分应该有效。但是,您定义泛型加法的部分问题更大,因为 Java 不允许您重载运算符“+”。所以以下将不会在 Java 中编译:

T add(T x, T y) {
    return x + y; // compile error -> no '+' defined for T
}

如果您需要 T 作为基本类型,您需要为每个要使用的基本类型定义 f1f2。另见这个问题:Can I do arithmetic operations on the Number baseclass?