概述
你的第二个和第三个项目符号(使用X.equals(Object)或回退到Object.equals(Object))不需要任何努力,因为无论如何在调用可覆盖的方法Object.equals(Object)时会发生什么,它将使用它能找到的最具体的重写方法.
因此,唯一剩下的任务是调用X.equals(X)方法(如果适用).要最小化相关成本,您可以缓存结果.从Java 7开始,有一个类ClassValue允许将信息与类相关联,以线程安全,懒惰评估和高效查找方式,仍然支持密钥类的垃圾收集(如果需要).
因此,Java 7解决方案可能如下所示:
import java.lang.invoke.*;
public final class EqualsOperation extends ClassValue {
public static boolean equals(Object o, Object p) {
if(o == p) return true;
if(o == null || p == null) return false;
Class> t1 = o.getClass(), t2 = p.getClass();
if(t1 != t2) t1 = commonClass(t1, t2);
try {
return (boolean)OPS.get(t1).invokeExact(o, p);
} catch(RuntimeException | Error unchecked) {
throw unchecked;
} catch(Throwable ex) {
throw new IllegalStateException(ex);
}
}
private static Class> commonClass(Class> t1, Class> t2) {
while(t1 != Object.class && !t1.isAssignableFrom(t2)) t1 = t1.getSuperclass();
return t1;
}
static final EqualsOperation OPS = new EqualsOperation();
static final MethodHandle FALLBACK;
static {
try {
FALLBACK = MethodHandles.lookup().findVirtual(Object.class, "equals",
MethodType.methodType(boolean.class, Object.class));
} catch (ReflectiveOperationException ex) {
throw new ExceptionInInitializerError(ex);
}
}
@Override
protected MethodHandle computeValue(Class> type) {
try {
return MethodHandles.lookup()
.findVirtual(type, "equals", MethodType.methodType(boolean.class, type))
.asType(FALLBACK.type());
} catch(ReflectiveOperationException ex) {
return FALLBACK;
}
}
}
你可以测试一下
Object[] examples1 = { 100, "foo",
new Area(new Rectangle(10, 20)), new Area(new Rectangle(20, 20)) };
Object[] examples2 = { new Integer(100), new String("foo"),// enforce a!=b
new Area(new Rectangle(10, 20)) };
for(Object a: examples1) {
for(Object b: examples2) {
System.out.printf("%30s %30s: %b%n", a, b, EqualsOperation.equals(a, b));
}
}
从Java 8开始,我们可以在运行时生成功能接口的实例,这可能会提高性能,因为在第一次遇到类型后,我们不再执行任何反射操作了:
import java.lang.invoke.*;
import java.util.function.BiPredicate;
public final class EqualsOperation extends ClassValue> {
public static boolean equals(Object o, Object p) {
if(o == p) return true;
if(o == null || p == null) return false;
Class> t1 = o.getClass(), t2 = p.getClass();
if(t1 != t2) t1 = commonClass(t1, t2);
return OPS.get(t1).test(o, p); // test(...) is not reflective
}
private static Class> commonClass(Class> t1, Class> t2) {
while(t1 != Object.class && !t1.isAssignableFrom(t2)) t1 = t1.getSuperclass();
return t1;
}
static final EqualsOperation OPS = new EqualsOperation();
static final BiPredicate FALLBACK = Object::equals;
@Override
protected BiPredicate computeValue(Class> type) {
if(type == Object.class) return FALLBACK;
try {
MethodType decl = MethodType.methodType(boolean.class, type);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(type, "equals", decl);
decl = mh.type();
BiPredicate p = (BiPredicate)
LambdaMetafactory.metafactory(lookup, "test",
MethodType.methodType(BiPredicate.class), decl.erase(), mh, decl)
.getTarget().invoke();
return p;
} catch(Throwable ex) {
return FALLBACK;
}
}
}
用法与其他变体一样.
这里的一个关键点是可访问性.我假设,你只想支持公共类声明的公共方法.尽管如此,如果越过模块边界,Java 9可能还需要进行微调.为了支持在应用程序代码中声明的自定义X.equals(X)方法,可能需要将自己打开到库中以进行反射访问.
在您的问题的评论中已经讨论了与其他代码(如集合)的相等逻辑不匹配的等式函数的问题.这里,类似的问题,例如,可能会出现IdentityHashMap;小心轻放…
最后
以上就是迅速母鸡为你收集整理的Java反射解决方法重载_用于调用重载方法的Java反射Area.equals(Area)的全部内容,希望文章能够帮你解决Java反射解决方法重载_用于调用重载方法的Java反射Area.equals(Area)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复