java为何重复调用方法_通过反射调用Java中的getter:重复调用它的最快方法是什么(在性能和可伸缩性方面)?...

小编典典

您可以使用MethodHandle。其Javadoc写道:

使用Lookup API中的工厂方法,可以将Core Reflection

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

更新:正如Irreputable所指出的那样,服务器VM具有一些不同的性能特征,因此

,仅当您可以将MethodHandle放在静态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

我建议您衡量您的特定用例。

2020-09-18

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值