直接上代码:
package com.example.demo;
import com.esotericsoftware.reflectasm.MethodAccess;
import lombok.Data;
import lombok.Getter;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import sun.reflect.MethodAccessor;
import java.beans.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
public class DemoApplication {
@Test
public void reflect() throws Throwable {
User user = new User();
user.age="111";
user.name = "bb";
Instant st = Instant.now();
for (int i = 0; i <10000000 ; i++) {
Class clz = user.getClass();
Method[] methods = clz.getMethods();
for (int j = 0; j <methods.length-9 ; j++) {
Method method = methods[j];
try {
Object invoke = method.invoke(user);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
System.out.println("原生耗时"+ Duration.between(st,Instant.now()).toMillis());
Instant st2 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());
for (PropertyDescriptor pdsc : beanInfo.getPropertyDescriptors()) {
pdsc.getReadMethod().invoke(user);
}
}
System.out.println("Introspector耗时"+ Duration.between(st2,Instant.now()).toMillis());
Instant st3 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
MethodHandles.Lookup lookup = MethodHandles.lookup();
//方法类型表示接受的参数和返回类型(第一个参数是返回参数)
MethodType methodType = MethodType.methodType(Integer.TYPE);
// MethodHandle id = lookup.findVirtual(user.getClass(), "getId", methodType);
MethodHandle id = lookup.findVirtual(user.getClass(), "getId", methodType);
id.invoke(user);
MethodType nMethodType = MethodType.methodType(String.class);
MethodHandle name = lookup.findVirtual(user.getClass(), "getName", nMethodType);
name.invoke(user);
MethodType agemethodType = MethodType.methodType(String.class);
MethodHandle age = lookup.findVirtual(user.getClass(), "getAge", agemethodType);
age.invoke(user);
MethodType sexmethodType = MethodType.methodType(Integer.TYPE);
MethodHandle sex = lookup.findVirtual(user.getClass(), "getSex", sexmethodType);
sex.invoke(user);
}
System.out.println("方法句柄耗时"+ Duration.between(st3,Instant.now()).toMillis());
Instant st4 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
MethodAccess methodAccessor = MethodAccess.get(user.getClass());
Object id = methodAccessor.invoke(user, "getId",null);
Object name = methodAccessor.invoke(user, "getName",null);
Object age = methodAccessor.invoke(user, "getAge", null);
Object sex = methodAccessor.invoke(user, "getSex", null);
}
System.out.println("字节码耗时"+ Duration.between(st4,Instant.now()).toMillis());
}
@Getter
public static class User{
private int id;
public String name;
public String age;
private int sex;
}
}
打印:
原生耗时5766
Introspector耗时5335
方法句柄耗时73953
字节码耗时33166
第二种方式测试:
package com.example.demo;
import com.esotericsoftware.reflectasm.MethodAccess;
import lombok.Getter;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
public class ReflectTest {
@Test
public void reflect() throws Throwable {
User user = new User();
user.age="111";
user.name = "bb";
Instant st = Instant.now();
for (int i = 0; i <10000000 ; i++) {
Class clz = user.getClass();
Method exec = clz.getMethod("exec", String.class);
exec.invoke(user,"222");
}
System.out.println("原生耗时"+ Duration.between(st,Instant.now()).toMillis());
Instant st2 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
for (MethodDescriptor methodDescriptor : methodDescriptors) {
Method method = methodDescriptor.getMethod();
if(method.getName().equals("exec"))
method.invoke(user,"3333");
}
}
System.out.println("Introspector耗时"+ Duration.between(st2,Instant.now()).toMillis());
Instant st3 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
MethodHandles.Lookup lookup = MethodHandles.lookup();
//方法类型表示接受的参数和返回类型(第一个参数是返回参数)
MethodType methodType = MethodType.methodType(Void.TYPE,String.class);
MethodHandle id = lookup.findVirtual(user.getClass(), "exec", methodType);
id.invoke(user,"222");
}
System.out.println("方法句柄耗时"+ Duration.between(st3,Instant.now()).toMillis());
Instant st4 = Instant.now();
for (int i = 0; i <10000000 ; i++) {
MethodAccess methodAccessor = MethodAccess.get(user.getClass());
Object id = methodAccessor.invoke(user, "exec","aa");
}
System.out.println("字节码耗时"+ Duration.between(st4,Instant.now()).toMillis());
}
@Getter
public static class User{
private int id;
public String name;
public String age;
private int sex;
public void exec(String aa){
this.name = aa;
}
}
}
打印:
原生耗时4784
Introspector耗时9276
方法句柄耗时17882
字节码耗时28180
解释说明:
以上代码可能有写法问题,与实际预期不相符。
个人预期:
- 字节快于=>Introspector快于=>方法句柄快于=>原生
官网说MethodHandles(方法句柄应该是高于原生反射的),字节码应该是最快的。
最终说明Introspector(逻辑中有缓存)始终是最快的。