使用反射调用方法与直接调用方法有什么不同?
上下文详细信息:我有一个类,具有一些字符串属性,对于某些属性,我必须将值设置为小写或Upper (以及一些与此相关的逻辑)。
我有两个选择:
当然,使用选项2,我的代码将更易读和易于维护,但问题是性能问题。我将有数以百万计的实例(约2-3个),如果性能影响不超过20秒,我将使用反射选项。
这里有人对此有什么经验吗?
发布于 2015-02-05 11:24:26
很难给出一个设定的数字,因为它将取决于系统的许多方面,所以我编写了一个类来检查这一点。
结果让我感到惊讶,对于我的系统来说,简单地通过反射调用方法与静态调用方法相比,静态调用对于非空方法来说是10,000倍,对于空方法则是100,000倍。
我同时使用了这两种方法,以防java编译器/vm正在优化空方法调用。
代码在下面,也可以在这个gist - https://gist.github.com/piersy/23b4814eec806b584266中找到。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestReflection {
public static long INC = 0;
public static final int COUNT = 100000000;
private static class Dummy {
public void doSomething(String s1, String s2, String s3) {
INC++;
}
}
public static void main(String[] args) throws NoSuchMethodException {
Dummy obj = new Dummy();
Method method = obj.getClass().getMethod("doSomething", String.class, String.class, String.class);
String s1 = "string1";
String s2 = "string2";
String s3 = "string3";
//warmup
runReflection(obj, method, s1, s2, s3, COUNT / 10);
runStatic(obj, s1, s2, s3, COUNT/10);
///realtest
long reftime = System.nanoTime();
runReflection(obj, method, s1, s2, s3, COUNT);
reftime = System.nanoTime() - reftime;
long time = System.nanoTime();
runStatic(obj, s1, s2, s3, COUNT);
time = System.nanoTime() - time;
System.out.println(reftime);
System.out.println(time);
//1000 *1000 *1000 nanoseconds in a second
System.out.println(reftime / (1000 *1000 *1000));
System.out.println(time / (1000 *1000 *1000));
System.out.println((double)reftime/ (double)time );
System.out.println("percentage speed decrease from using reflection:"+(((double)reftime/(double)time)-1)*100);
}
private static void runReflection(Dummy obj, Method method, String s1, String s2, String s3, int count) {
for (int i = 0; i < count; i++) {
try {
method.invoke(obj, s1, s2, s3);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
private static void runStatic(Dummy obj, String s1, String s2, String s3, int count) {
for (int i = 0; i < count; i++) {
obj.doSomething(s1,s2,s3);
}
}
}发布于 2014-08-19 17:02:55
一般来说,是的,反射要慢一些。如果数百万实例是指数百万次呼叫,那么是的,在某些情况下,您可能会产生超过20秒的开销。在某些原因中,您可能不会产生额外的开销,因为编译器将能够优化它。您必须提供更多关于如何使用反射的详细信息,或者自己运行它。我的直觉说,在300万次通话中,你不会超过20秒的开销,然而,这在很大程度上是直觉。
发布于 2014-08-19 17:11:55
让我们从Oracle Docs反射的一些缺点开始
反射的缺陷 反射是强大的,但不应任意使用。如果可以不使用反射来执行操作,那么最好避免使用它。在通过反射访问代码时,应该记住以下几点。 由于反射涉及动态解析的类型,因此无法执行某些虚拟机优化。因此,反射操作的性能比它们的非反射操作要慢,在性能敏感的应用程序中经常调用的代码部分应该避免反射操作。 安全限制反射要求在安全管理器下运行时可能不存在的运行时权限。这是对必须在受限的安全上下文中运行的代码的一个重要考虑,例如在Applet中。 因为反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,反射的使用可能导致意外的副作用,这可能会导致代码功能失调,并可能破坏可移植性。反射代码破坏抽象,因此可能会随着平台的升级而改变行为。
因此,您可以确信,一旦开始扩展,性能就会成为一个问题。但是,如果您可以忍受性能开销(直觉说,大写/小写操作不应该超过20秒),并且具有很大的可伸缩性,那么您可以使用它。但请注意,对性能的直觉通常都是错误的。所以你肯定想测试一下。
为您想要的任务查找面向方面的编程。
我的观点是:使用AOP框架。
https://stackoverflow.com/questions/25388938
复制相似问题