有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

}

现在我可以将它设置为一个静态方法,但是有没有一种方法可以将不同的静态方法传递到这个计算中,而不是为我要测试的每个方法创建一个静态方法?如果没有,是否有一种设计模式可以在这里工作?到目前为止,我正在为每一个我想要计时的方法创建一个这样的方法,但它似乎并不高效,因为我重用了太多的代码


共 (5) 个答案

  1. # 1 楼答案

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

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

    这样称呼它:

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

    您可能还想从How do I write a correct micro-benchmark in Java?

    中考虑一些技巧。
  2. # 2 楼答案

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

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

    和另一个MeasureUtilutil类,其中的方法接受类型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,这使得使用sugar语法变得更加简单和容易:

    long avg = MeasureUtil.calculateAvg(() -> method_under_mesure());
    
  3. # 3 楼答案

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

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

    在main方法中,有3种方法可以通过该方法。假设您想在SelectionSort类中测试静态排序方法

    第一:匿名类(传统方式)

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

    第二名:Lambda(Java 8)

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

    第三:方法引用Java 8 Method Reference: How to Use it

    calculateAvg(SelectionSort::sort)
    
  4. # 4 楼答案

    对于这个问题,我有两种解决方案:
    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方法前后的时间proxy pattern tutorials

  5. # 5 楼答案

    您不能“传递方法”,静态或非静态。相反,您需要创建从包含该方法的类创建的对象引用。然后调用对象引用上的方法。为了提供方法的不同实现,您需要创建一个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);