繁体   English   中英

在Java中传递静态方法

[英]Pass static methods in Java

我试图创建一个类,该类乘以一个方法的平均运行时间。 我了解如何通过运行100次并取平均值来做到这一点。 例:

private long calculateAvg(){
    long totalTime = 0;

    for(int i = 0; i < ITERATIONS; i++){
        long startTime = System.nanoTime();
        testMethod();
        long endTime = System.nanoTime();

        totalTime += (endTime - startTime);  //divide by 1000000 to get milliseconds.
    }
    return (totalTime / ITERATIONS);

}

现在,我可以将其设置为适用于一个静态方法,但是有一种方法可以将不同的静态方法传递给该方法以进行计算,而不是为我要测试的每种方法创建其中一种方法? 如果没有,有没有可以在这里使用的设计模式? 到目前为止,我正在为我想计时的所有其他方法创建这些方法之一,但由于我正在重用大量代码,因此似乎效率不高。

您可以接受并运行Runnable参数:

private long calculateAvg(Runnable r) {
    //...
    long startTime = System.nanoTime();
    r.run();
    long endTime = System.nanoTime();
    //...
}

并这样称呼它:

long avg1 = calculateAvg(() -> testMethod());
long avg2 = calculateAvg(() -> testMethod2());

您可能还需要考虑如何使用Java编写正确的微基准测试中的一些技巧

您不能“传递方法”,静态或非静态。 相反,您需要创建一个从包含该方法的类创建的对象引用。 然后,在对象引用上调用该方法。 为了提供方法的不同实现,请创建一个interface 然后,您可以有许多实现该接口及其声明的方法的类。 现在,您的计时代码使用该接口访问正确的方法。

public interface TheMethod {
    public void foo();
}

public class Method1 implements TheMethod {
    public void foo() {
        // code goes here 
    }
}

public class Method2 implements TheMethod {
    public void foo() {
        // code goes here 
    }
}

现在修改您的计时方法以接受TheMethod实例:

private long calculateAvg(TheMethod method){
    // ...
    method.foo();
    // ...
}

最后,您可以使用实现TheMethod的类的不同实例来调用此方法:

TheMethod m1 = new Method1();
TheMethod m2 = new Method2();

long x = calculateAvg(m1);
long y = calculateAvg(m2);

我有两个解决方案可能会对这个问题有所帮助:
1. Java反射

public long calculateAvg(Object obj, String methodName) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException{
    Method method = obj.getClass().getDeclaredMethod(methodName);
    method.setAccessible(true);

    long totalTime = 0;
    for(int i = 0; i < ITERATIONS; i++) {
        long startTime = System.nanoTime();
        method.invoke(obj);
        long endTime = System.nanoTime();

        totalTime += (endTime - startTime);  //divide by 1000000 to get milliseconds.
    }
    return (totalTime / ITERATIONS);
}
  1. 代理模式

您可以了解proxy pattern ,无需自己调用真正的方法,代理即可。 您可以在调用real方法之前和之后获得时间。 代理模式教程

不,您不能在Java中传递方法,因为方法不是Java中的一等公民,它们也不是values 解决此类问题的模式是使用anonymous class 以您的情况为例,您可以定义一个interface

@FunctionalInterface  // this annotation is available since jdk1.8
public interface Measurable {
    void measure();
}

还有另一个MeasureUtil util类,其中的方法接受Measurable类型:

    public class MeasureUtil {
    private static final long ITERATIONS = 1000;

    public static long calculateAvg(Measurable measurable) {
        long totalTime = 0;

        for(int i = 0; i < ITERATIONS; i++){
            long startTime = System.nanoTime();
            measurable.measure();
            long endTime = System.nanoTime();

            totalTime += (endTime - startTime);  //divide by 1000000 to get milliseconds.
        }
        return (totalTime / ITERATIONS);
    }
}

然后,您new一个Measurable实例,并将其每次传递给MeasureUtil.calculateAvg

    public class Main {
    public static void main(String[] args) {
        long avg = MeasureUtil.calculateAvg(new Measurable() {
            @Override
            public void measure() {
                method_under_mesure();
            }
        });
        System.out.println("Avg: " + avg);
    }

    private static void method_under_mesure() {
        System.out.println("call me");
    }
}

自从jdk1.8 Java开始支持lambda expression以来,使用语法糖可以使其变得更加简单:

long avg = MeasureUtil.calculateAvg(() -> method_under_mesure());

根据您的输入,您的方法应该是这样的

private long calculateAvg(Testable t){
  long totalTime = 0;

  for(int i = 0; i < ITERATIONS; i++){
    long startTime = System.nanoTime();
    t.testMethod();
    long endTime = System.nanoTime();

    totalTime += (endTime - startTime);  //divide by 1000000 to get milliseconds.
  }
  return (totalTime / ITERATIONS);
}

然后,您应该有一个具有单个方法的接口:

public interface Testable {
    public void testMethod();
}

在您的主要方法中,您有3种方法来传递方法。 假设您要在SelectionSort类中测试静态排序方法。

第一:匿名课堂(传统方式)

calculateAvg(new Testable(){
    @Override
    public void testMethod(){
       SelectionSort.sort();
    }
})

第二:Lambda(Java 8)

calculateAvg(() -> SelectionSort.sort())

第三章:方法参考Java 8方法参考:如何使用它

calculateAvg(SelectionSort::sort)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM