【问题标题】:C++ functors to Java, overloading operator ()()C++ 函子到 Java,重载运算符 ()()
【发布时间】:2016-08-17 20:35:17
【问题描述】:

假设一个简单的 C++ 函子示例:

class Test2 {
    private:
        double a;

    public:
        Test2 (double a_) : a(a_){}
        double operator () () {return 10*a;}
};

template <typename Function>
double test ( Function function ) {return function();}

int main(int argc,  char* argv[]) {
    double a = test( Test2(5) );
    return 0;
}

有没有办法在 Java 中实现这种构造(例如使用接口 Functor)?你能给我一个简短的例子吗?感谢您的帮助。

【问题讨论】:

  • 目前还不清楚您真正要完成的是什么。这似乎是一个简单的 lambda 案例。
  • @chrylis 没有羔羊可以吗?功能可能比较复杂...
  • 为什么需要这样做?为什么不Test2(5).test()
  • @ 4castle 我正在使用函子“注入”计算所需的补充数据。运算符 ()() 执行一些复杂的矩阵运算,矩阵是根据这些数据构造的。该代码代表了一个显着简化的示例。
  • @Jesper 谢谢...有没有不同的方法(Java 很自然)来表达这种关系?

标签: java c++ interface operators functor


【解决方案1】:

在 Java 8 中,您可以使用 DoubleSupplier 接口从对象中获取 double 值:

public class Test implements DoubleSupplier {
    private double a;
    public Test(double a) { this.a = a; }
    public double getAsDouble() { return 10 * a; }

    public static double test(DoubleSupplier ds) { 
        return ds.getAsDouble();
    }
    public static void main(String[] args) {
        double a = test(new Test(5));
    }
}

如果您不使用 Java 8,那么您可以制作自己的接口来实现:

public interface MyDoubleSupplier {
    double getAsDouble();
}

【讨论】:

  • 有趣的解决方案,与 C++ 完全不同的方法:-)
  • 其实挺像的。不是使用() 来执行它,而是使用.getAsDouble() 来执行它。否则,对于相同的结果,只是语法和名称略有不同。
  • 它是否适用于类似于 getAsDouble 的静态方法或传递给此方法的一些附加参数(不涉及构造函数)?
  • 如果您使用静态方法,您将无法再使用多态性来完成任务。换句话说,您必须对所有方法调用进行硬编码。您最好将它们作为对象保留。是的,您可以添加其他参数,但您将无法使用DoubleSupplier 接口。您将不得不使用自己的自定义界面。您可以根据需要更改所有这些参数。由于 Java 严重依赖于面向对象的编程,您可能需要使用一些教程以使一切更有意义。
【解决方案2】:

在 Java 中没有完全相同的等价物,因为没有什么能像在 C++ 中那样重载 () 的含义。

从 Java 8 开始,您可以在 Java 中以函数式风格进行编程,并且包 java.util.function 中有许多标准函数式接口。

你可以这样做:

import java.util.function.DoubleSupplier;

public double test(DoubleSupplier supplier) {
    return supplier.getAsDouble();
}

public DoubleSupplier newSupplier(double a) {
    return () -> 10 * a;
}

// use it:
double a = test(newSupplier(5));

【讨论】:

    【解决方案3】:

    你不会在 Java 中得到完全相同的东西,但你所做的事情的原则应该是一样的。

    如果你想要一个可以像functor_obj() 这样调用的Java 函子,那是不可能的。 Java 不允许运算符重载*,所以这种语法根本不可能。

    然而,Java 8 引入了“函数式接口”的概念,它被定义为任何只有一个 [抽象**] 函数的接口。每当您使用函数式接口时,它的实例化都可以替换为 lambda 表达式。

    Runnable run = () -> {System.out.println("Hello World (FROM THE SECOND DIMEN—I mean THREAD)");};
    Thread thread = new Thread(run); 
    //Also Equivalent to the two above lines:
    //Thread thread = new Thread(() -> {System.out.println("Hello World (FROM THE SECOND DIMEN—I mean THREAD)");});
    thread.start();
    thread.join();
    

    如果你想调用这个特定的函子,你只需像调用任何其他实现接口的对象一样调用它:

    run.run();
    

    因为 Java Lambda 表达式所做的是隐藏实现。以下代码:

    Runnable run = () -> {System.out.println("Hello World (FROM THE SECOND DIMEN—I mean THREAD)");};
    

    与 Java 7 等效代码做同样的事情:

    Runnable run = new Runnable() {
        public void run() {
            System.out.println("Hello World (FROM THE SECOND DIMEN—I mean THREAD)");
        }
    };
    

    所以对于你的例子,你可能会这样写:

    public static double test(Supplier<Double> f) {//imported from java.util.function
        return f.get();
    }
    

    然后可以这样调用:

    double a = test(() -> 25);
    

    这相当于您在原始main 函数中编写的代码。如果你需要存储函子以备将来使用,你可以这样写:

    Supplier<Double> sup = () -> 25;
    double a = test(sup);
    /*sup can now be stored somewhere or passed to a different function.*/
    

    * - 我的意思是,Java 确实有 String 对象的运算符重载,以允许使用 + 连接对象,但这几乎是唯一使用它的情况。

    ** - Java 8 还为接口引入了“默认”方法,它允许接口具有实现的方法。这可能看起来很奇怪,直到您意识到它可以让您编写诸如 public default void sort() 之类的内容,这些内容可以添加到 java.util.List&lt;T&gt; 以允许使用通用的通用算法对具有访问器和删除操作的所有列表进行排序。

    【讨论】:

      猜你喜欢
      • 2021-07-10
      • 2011-11-14
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      相关资源
      最近更新 更多