闲逛的时候看见一篇文章
本来,是去瞧瞧有什么优化的?毕竟平常反射是最常用的,而且用的很多,怎么还有更方便的方法?
没想到还真有是吧,好好好。
然后,我查查找找写了下面四个方法,都可以直接调用对象的get方法(不理解的东西可以点链接先了解,了解,嘿嘿嘿)
看完,又可以装13了,O(∩_∩)O哈哈~
方法一:通过SerializedLambda获取到方法信息,再使用MethodHandle拿到方法句柄执行方法
ini
static Pattern RETURN_TYPE_PATTERN = Pattern.compile("^\(\)L(.*);");
public static <T> Object myInvokeGetter(T target, SerializableFunction<T, ?> func) {
long l = System.currentTimeMillis();
System.out.println("-->" + l);
Object obj = null;
try {
SerializedLambda resolve = getSerializedLambda(func);
String methodName = resolve.getImplMethodName();
String expr = resolve.getImplMethodSignature();
Matcher matcher = RETURN_TYPE_PATTERN.matcher(expr);
if (!matcher.find() || matcher.groupCount() != 1) {
throw new RuntimeException("获取Lambda信息失败");
}
String className = matcher.group(1).replace("/", ".");
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle virtual = lookup.findVirtual(target.getClass(), methodName, MethodType.methodType(Class.forName(className)));
obj = virtual.invoke(target);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("-->" + (System.currentTimeMillis() - l));
return obj;
}
public static <T, R> SerializedLambda getSerializedLambda(Function<T, R> function) {
SerializedLambda invoke = null;
try {
Method method = function.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
invoke = (SerializedLambda) method.invoke(function);
} catch (Exception e) {
e.printStackTrace();
}
return invoke;
}
public static void main(String[] args) throws Throwable {
OrderJackyun obj = new OrderJackyun();
obj.setIsSalesAndOutAudit(1);
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter(obj,OrderJackyun::getIsSalesAndOutAudit);
}
方法二:同样是通过SerializedLambda获取到方法信息,不过是使用再使用LambdaMetafactory.metafactory(),方法结合MethodHandle、MethodType、Function执行方法
ini
static Pattern RETURN_TYPE_PATTERN = Pattern.compile("^\(\)L(.*);");
public static <T> Object myInvokeGetter2(T target, SerializableFunction<T, ?> func) {
long l = System.currentTimeMillis();
System.out.println("-->" + l);
Object apply = null;
try {
SerializedLambda resolve = getSerializedLambda(func);
String methodName = resolve.getImplMethodName();
String expr = resolve.getImplMethodSignature();
Matcher matcher = RETURN_TYPE_PATTERN.matcher(expr);
if (!matcher.find() || matcher.groupCount() != 1) {
throw new RuntimeException("获取Lambda信息失败");
}
String className = matcher.group(1).replace("/", ".");
MethodHandles.Lookup lookup = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
lookup.findVirtual(target.getClass(), methodName, MethodType.methodType(Class.forName(className))),
MethodType.methodType(Class.forName(className), target.getClass()));
Function function = (Function) ((CallSite) site).getTarget().invokeExact();
apply = function.apply(target);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("-->" + (System.currentTimeMillis() - l));
return apply;
}
public static <T, R> SerializedLambda getSerializedLambda(Function<T, R> function) {
SerializedLambda invoke = null;
try {
Method method = function.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
invoke = (SerializedLambda) method.invoke(function);
} catch (Exception e) {
e.printStackTrace();
}
return invoke;
}
public static void main(String[] args) throws Throwable {
OrderJackyun obj = new OrderJackyun();
obj.setIsSalesAndOutAudit(1);
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter2(obj,OrderJackyun::getIsSalesAndOutAudit);
}
第三种:直接使用反射执行方法
ini
public static <T> Object myInvokeGetter3(T target, String name) {
long l = System.currentTimeMillis();
System.out.println("-->" + l);
Object invoke = null;
try {
Method method = target.getClass().getMethod("get" + StringUtils.capitalize(name));
invoke = method.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("-->" + (System.currentTimeMillis() - l));
return invoke;
}
public static void main(String[] args) throws Throwable {
OrderJackyun obj = new OrderJackyun();
obj.setIsSalesAndOutAudit(1);
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter3(obj,"isSalesAndOutAudit");
}
第四种:hutool工具包提供的工具类,使用反射执行方法
ini
public static <T> Object myInvokeGetter4(T target, String name) {
long l = System.currentTimeMillis();
System.out.println("-->" + l);
Object invoke = ReflectUtil.invoke(target, "get" + StringUtils.capitalize(name));
System.out.println("-->" + (System.currentTimeMillis() - l));
return invoke;
}
public static void main(String[] args) throws Throwable {
OrderJackyun obj = new OrderJackyun();
obj.setIsSalesAndOutAudit(1);
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter4(obj,"isSalesAndOutAudit");
}
当然,方法有了,结果呢?(简单不严谨的测测)
第一和第二方法相差不大,大致都是3-9毫秒,一般维持在5-6左右
第三种差不多是上面两种时间的两倍,大致都是10-20毫秒,一般维持在10-15左右
第四种就比较久了,大致都是30-60毫秒,一般维持在50以上左右
但是不管是哪种方式都是第一次调用的时候耗时是这么久,连续的调用后面都是接近0毫秒
ini
public static void main(String[] args) throws Throwable {
OrderJackyun obj = new OrderJackyun();
obj.setIsSalesAndOutAudit(1);
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter4(obj,"isSalesAndOutAudit");
Integer value1 = (Integer) HyReflectUtils.myInvokeGetter4(obj,"isSalesAndOutAudit");
}
比如这种,第二次甚至多次(并不局限这个属性也可以是其他属性)都是1或者0毫秒
最后:hutool工具包因为是提供的公用方法,考虑和验证的地方比较多,会慢也是正常, 同时,去查看反射的invoke方法执行,你会发现到最后还是会通过MethodHandle去调用
invoke:源码
typescript
public static <T> T invoke(Object obj, String methodName, Object... args) throws UtilException {
Assert.notNull(obj, "Object to get method must be not null!", new Object[0]);
Assert.notBlank(methodName, "Method name must be not blank!", new Object[0]);
Method method = getMethodOfObj(obj, methodName, args);
if (null == method) {
throw new UtilException("No such method: [{}] from [{}]", new Object[]{methodName, obj.getClass()});
} else {
return invoke(obj, method, args);
}
}
上面方法的下一步
ini
public static <T> T invoke(Object obj, Method method, Object... args) throws UtilException {
setAccessible(method);
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] actualArgs = new Object[parameterTypes.length];
if (null != args) {
for(int i = 0; i < actualArgs.length; ++i) {
if (i < args.length && null != args[i]) {
if (args[i] instanceof NullWrapperBean) {
actualArgs[i] = null;
} else if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
Object targetValue = Convert.convert(parameterTypes[i], args[i]);
if (null != targetValue) {
actualArgs[i] = targetValue;
}
} else {
actualArgs[i] = args[i];
}
} else {
actualArgs[i] = ClassUtil.getDefaultValue(parameterTypes[i]);
}
}
}
if (method.isDefault()) {
return MethodHandleUtil.invokeSpecial(obj, method, args);
} else {
try {
return method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs);
} catch (Exception var7) {
throw new UtilException(var7);
}
}
}
下一步,上面方法的MethodHandleUtil.invokeSpecial()方法执行源码,在这你就发现熟悉的MethodHandle以及lookup,只不过这里是直接通过方法获取对应的句柄。
ini
public static <T> T invoke(boolean isSpecial, Object obj, Method method, Object... args) {
Assert.notNull(method, "Method must be not null!", new Object[0]);
Class<?> declaringClass = method.getDeclaringClass();
Lookup lookup = lookup(declaringClass);
try {
MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass) : lookup.unreflect(method);
if (null != obj) {
handle = handle.bindTo(obj);
}
return handle.invokeWithArguments(args);
} catch (Throwable var7) {
throw new UtilException(var7);
}
}
感谢: