在Java中传递静态方法

在Java中传递静态方法,java,Java,我试图创建一个类,该类的运行时间是方法的平均运行时间的倍。我知道如何做到这一点,运行了100次,并将其全部取平均值。例如: private long calculateAvg(){ long totalTime = 0; for(int i = 0; i < ITERATIONS; i++){ long startTime = System.nanoTime(); testMethod(); long endTime = S

我试图创建一个类,该类的运行时间是方法的平均运行时间的倍。我知道如何做到这一点,运行了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);

}
private long calculateAvg(){
长总时间=0;
对于(int i=0;i

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

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

private long calculateAvg(Runnable r) {
    //...
    long startTime = System.nanoTime();
    r.run();
    long endTime = System.nanoTime();
    //...
}
这样称呼它:

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

您可能还想从

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

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 
    }
}
现在修改计时方法,以接受
method
实例:

private long calculateAvg(TheMethod method){
    // ...
    method.foo();
    // ...
}
最后,您可以使用实现方法的类的不同实例调用此方法:

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);
}
public long calculateAvg(Object obj,String methodName)抛出NoSuchMethodException、SecurityException、IllegalAccessException、IllegalArgumentException、InvocationTargetException、ClassNotFoundException{
方法Method=obj.getClass().getDeclaredMethod(方法名);
方法setAccessible(true);
长总时间=0;
对于(int i=0;i
  • 代理模式

  • 您可以学习
    代理模式
    ,您不需要自己调用真正的方法,代理可以。您可以获得调用real方法前后的时间

    不,您不能在Java中传递方法,因为方法不是Java中的第一类公民,它们不是
    值。解决此类问题的模式是使用
    匿名类
    。以您的案例为例,您可以定义一个
    接口

    @FunctionalInterface  // this annotation is available since jdk1.8
    public interface Measurable {
        void measure();
    }
    
    和另一个
    MeasureUtil
    util类,其中的方法接受类型
    measured

        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);
        }
    }
    
    由于jdk1.8 Java开始支持
    lambda表达式
    ,这使得使用sugar语法变得更加简单和容易:

    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);
    }
    
    在main方法中,有3种方法可以通过该方法。假设您想在SelectionSort类中测试静态排序方法

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

    第二名:Lambda(Java 8)

    第三:方法参考


    您正在使用Java8吗?试过
    函数
    类吗?我正在使用java 8,但我没有试过这两种建议。我将不得不研究每一个都做什么。使用一个界面。非常有趣。
    ()->
    是否使其成为可运行的参数?是的,它是lambda。如果愿意,您也可以使用方法引用或匿名类。@Code peedient-error。它们适用于没有返回值且不带参数的方法的任何用途。请注意,当Java8引入lambdas和方法引用时,它们还为采用0、1或2个参数并返回或不返回结果的方法添加了许多标准化的接口定义。但是他们没有为没有参数和结果的方法定义接口。为什么他们没有?因为Java已经有了
    Runnable
    ,您还可以保存
    calculateAvg(TestClass::testMethod)
    如果
    TestClass
    定义了静态方法
    testMethod()
    ,没有参数或结果。@shmosel为了改进您的答案,您可以同时显示“老派”匿名内部类方法和lambda方法。然后再解释一下差异。(我之所以这样建议,是因为OP对Java来说似乎非常陌生,而且肯定应该了解更多关于接口和类的知识。)我认为这是错误的
    method.invoke(clazz)
    似乎假定
    method
    Class
    类的一个方法,而它通常不是。是的,您应该将类实例作为该方法所属的参数传递。我不确定您在说什么。关键是,这个密码被破解了。它不会以你现有的形式工作。
    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();
    }
    
    calculateAvg(new Testable(){
        @Override
        public void testMethod(){
           SelectionSort.sort();
        }
    })
    
    calculateAvg(() -> SelectionSort.sort())
    
    calculateAvg(SelectionSort::sort)