在使用反射的情况下,我们通过以诸如m = getMethod("someMethod")
这样的字符串编码的名称访问实体。为了找到所请求的实体,必须进行字符串比较。这是否意味着实体名称的长度会影响性能。如果这样对性能有多大影响?
答案 0 :(得分:1)
答案很大程度上取决于您使用的Java虚拟机。我编写了一个测试程序,只是为了获取JVM 1.8.0_05的一些数字(是的,它很旧了;-):
import java.lang.reflect.Method;
public class ReflectionAccessTest {
public final static void main(String[] args) throws Exception {
for (int i = 0; i < 100000; i++) {
// do some "training"
ReflectionTarget.class.getMethod("a", Integer.TYPE, Integer.TYPE);
ReflectionTarget.class.getMethod("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Integer.TYPE, Integer.TYPE);
ReflectionTarget.class.getMethod("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Integer.TYPE, Integer.TYPE);
}
Method method = null;;
long start;
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
// do some "training"
method = ReflectionTarget.class.getMethod("a", Integer.TYPE, Integer.TYPE);
}
System.out.println("Time to get method with short name " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
method.invoke(null, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
System.out.println("Time to execute method with short name " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
// do some "training"
method = ReflectionTarget.class.getMethod("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Integer.TYPE, Integer.TYPE);
}
System.out.println("Time to get method with medium name " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
method.invoke(null, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
System.out.println("Time to execute method with medium name " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
// do some "training"
method = ReflectionTarget.class.getMethod("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Integer.TYPE, Integer.TYPE);
}
System.out.println("Time to get method with long name " + (System.currentTimeMillis() - start) + " ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
method.invoke(null, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
System.out.println("Time to execute method with long name " + (System.currentTimeMillis() - start) + " ms");
}
private static class ReflectionTarget {
public static void a(int a, int b) {
// do nothing
}
public static void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(int a, int b) {
// do nothing
}
public static void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(int a, int b) {
// do nothing
}
}
}
输出如下:
Time to get method with short name 1012 ms
Time to execute method with short name 58 ms
Time to get method with medium name 3690 ms
Time to execute method with medium name 177 ms
Time to get method with long name 6279 ms
Time to execute method with long name 180 ms
时间实际上取决于名称的长度(首先让我感到惊讶,但第二个想法是显而易见的,因为需要某种与长度有关的均等检验)。
但是您也可以看到影响可以忽略不计。对于名称只有一个字符的方法,调用getMethod
会花费0.1纳秒,而对于带有疯狂长名的方法(尚未计算a
的数目)的调用会花费0.6纳秒。 / p>
如果这种差异实际上与您有关,则可以尝试使用检索到的方法的缓存机制。但是取决于所调用方法所花费的时间,除非它的执行时间也在亚纳秒范围内,否则可能完全没有用。