[英]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);
}
您可以了解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.