给定一个类foo
和一个属性bar
(在编译时我都不知道这两个属性),我需要多次重复调用getterfoo.getbar()
。
假设我有:
Method barGetterMethod = ...; // Don't worry how I got this
for (Object foo : fooList) { // 1000000000 elements in fooList
Object bar = barGetterMethod.invoke(foo);
...
}
您可以使用MethodHandle。它的Javadoc写到:
使用查找API中的工厂方法,任何由核心反射API对象表示的类成员都可以转换为行为等效的方法句柄。例如,可以使用lookup.unreflect将反射方法转换为方法句柄。结果的方法句柄通常提供对基础类成员的更直接和更有效的访问。
虽然这将减少开销,但方法句柄仍然会阻止JVM在使用通常的(非反射的)字节代码指令进行调用时可以使用的某些优化(如方法内联)。这样的优化是否有益取决于您如何使用方法(如果代码路径总是调用相同的方法,内联可以提供帮助,如果每次都是不同的方法,可能不是这样)。
package tools.bench;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.math.BigDecimal;
public abstract class Bench {
final String name;
public Bench(String name) {
this.name = name;
}
abstract int run(int iterations) throws Throwable;
private BigDecimal time() {
try {
int nextI = 1;
int i;
long duration;
do {
i = nextI;
long start = System.nanoTime();
run(i);
duration = System.nanoTime() - start;
nextI = (i << 1) | 1;
} while (duration < 100000000 && nextI > 0);
return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return name + "\t" + time() + " ns";
}
static class C {
public Integer foo() {
return 1;
}
}
static final MethodHandle sfmh;
static {
try {
Method m = C.class.getMethod("foo");
sfmh = MethodHandles.lookup().unreflect(m);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
final C invocationTarget = new C();
final Method m = C.class.getMethod("foo");
final Method am = C.class.getMethod("foo");
am.setAccessible(true);
final MethodHandle mh = sfmh;
Bench[] marks = {
new Bench("reflective invocation (without setAccessible)") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += (Integer) m.invoke(invocationTarget);
}
return x;
}
},
new Bench("reflective invocation (with setAccessible)") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += (Integer) am.invoke(invocationTarget);
}
return x;
}
},
new Bench("methodhandle invocation") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += (Integer) mh.invokeExact(invocationTarget);
}
return x;
}
},
new Bench("static final methodhandle invocation") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += (Integer) sfmh.invokeExact(invocationTarget);
}
return x;
}
},
new Bench("direct invocation") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += invocationTarget.foo();
}
return x;
}
},
};
for (Bench bm : marks) {
System.out.println(bm);
}
}
}
在我有点过时的笔记本上
java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) Client VM (build 22.0-b10, mixed mode, sharing)
这将打印:
reflective invocation (without setAccessible) 568.506 ns
reflective invocation (with setAccessible) 42.377 ns
methodhandle invocation 27.461 ns
static final methodhandle invocation 9.402 ns
direct invocation 9.363 ns
更新:正如Irreportable所指出的,服务器VM有一些不同的性能特征,因此只有在您可以将其放在静态final字段中时,在服务器VM中使用MethodHandle才会有帮助,在这种情况下,VM可以内联调用:
reflective invocation (without setAccessible) 9.736 ns
reflective invocation (with setAccessible) 7.113 ns
methodhandle invocation 26.319 ns
static final methodhandle invocation 0.045 ns
direct invocation 0.044 ns
我建议您度量您的特定用例。
问题内容: 给定一个类和一个属性, 在编译时 我 都不知道 ,我需要多次多次调用getter 。 假设我有: 我需要做这样的事情: 与没有反射的调用相比,上述实现仍然非常慢。有没有更快的方法? 用Java在反射中调用吸气剂的最快方法是什么? 问题答案: 您可以使用MethodHandle。其Javadoc写道: 使用Lookup API中的工厂方法,可以将Core Reflection API对象
问题内容: 我试图通过反射获取静态私有属性的值,但失败并显示错误。 我得到的异常是: 而且,我需要使用以下代码来调用一个私有的。 但是问题是Student类是单例类,并且构造函数是私有的,并且无法访问。 问题答案: 您可以将字段设置为可访问:
问题内容: 我有这段代码在做Range Minimum Query 。当t = 100000时,i和j始终在每条输入行中更改,因此在Java 8u60中其执行时间约为12秒。 当我提取一个新方法以找到最小值时,执行时间快了4倍(约2.5秒)。 我一直认为方法调用很慢。但是这个例子却相反。Java 6也演示了这一点,但是在两种情况下(17秒和10秒)执行时间都慢得多。有人可以对此提供一些见识吗? 问
我有一段代码在做最小范围查询。当t=100000时,i和j在每个输入行中总是发生变化,其在Java8u60中的执行时间约为12秒。 当我提取一个新方法来寻找最小值时,执行时间快了4倍(大约2.5秒)。 我一直认为方法调用很慢。但是这个例子显示了相反的情况。Java6也演示了这一点,但是两种情况下的执行时间都要慢得多(17秒和10秒)。有人能对此提供一些见解吗?
本文向大家介绍Java通过PropertyDescriptor反射调用set和get方法,包括了Java通过PropertyDescriptor反射调用set和get方法的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了PropertyDescriptor反射调用set和get方法,供大家参考,具体内容如下 第一段: 第二段: 第三段: 以上就是本文的全部内容,希望对大家的学习有所帮助
问题内容: 我需要获取具有特定批注的字段的值,因此通过反射,我能够获取此Field Object。问题在于,尽管我事先知道它将始终具有getter方法,但该字段将始终是私有的。我知道我可以使用setAccesible(true)并获取其值(当没有PermissionManager时),尽管我更喜欢调用其getter方法。 我知道可以通过查找“ get + fieldName”来查找该方法(尽管例如