我正在编写一个应用程序,需要在运行时实现功能接口。我事先不知道要实现哪些接口,但可以Method使用接口Class对象的反射来解析对象。
为了简化问题,假设我传递一个Function包含该方法的实现的对象。
直接的东西:
@SuppressWarnings("unchecked")
private <T> T implement(Class<T> interfaceType, Method m, Function<Object[], ?> f) {
return (T) Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class<?>[]{interfaceType},
(proxy, method, args) -> {
if (method.equals(m)) {
return f.apply(args);
}
// Calls to toString, hashCode, and equals go here.
throw new UnsupportedOperationException(method.getName());
}
);
}
Run Code Online (Sandbox Code Playgroud)
因此,对toString、hashCode、 和 的调用equals当前失败。我显然不希望这样。
来自以下文档java.lang.reflect.Proxy:
代理实例上声明的
hashCode、equals或toString方法的调用java.lang.Object将被编码并分派到调用处理程序的调用方法,其方式与接口方法调用的编码和分派相同,如上所述。传递给调用的对象的声明类Method将为java.lang.Object。继承自的代理实例的其他公共方法java.lang.Object不会被代理类覆盖,因此这些方法的调用行为就像对java.lang.Object.
所以我可以根据需要重写这些方法。这很酷,但我宁愿不这样做。
当然,我可以制作虚拟实现,或多或少执行相同的操作(除了hashCodeis native)或捕获其他虚拟对象(可能是调用处理程序本身)并调用该对象上的方法。但我觉得我应该能够“放弃”从java.lang.Object通常方式继承的方法。或者换句话说,super.hashCode()直接在 上调用等价的内容proxy。
有没有好的/标准的方法来做到这一点?
根据评论中的建议,我最终定义了以下基本调用处理程序:
public class ObjectInvocationHandler implements InvocationHandler {
public static final Method HASH_CODE;
public static final Method EQUALS;
public static final Method TO_STRING;
static {
Class<Object> object = Object.class;
try {
HASH_CODE = object.getDeclaredMethod("hashCode");
EQUALS = object.getDeclaredMethod("equals", object);
TO_STRING = object.getDeclaredMethod("toString");
} catch (NoSuchMethodException e) {
// Never happens.
throw new Error(e);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
// The clone() method is not handled as there's no way to emulate the behavior of that method.
// Implementers would have to implement cloning entirely in a subclass.
if (method.equals(HASH_CODE)) {
return objectHashCode(proxy);
}
if (method.equals(EQUALS)) {
return objectEquals(proxy, args[0]);
}
if (method.equals(TO_STRING)) {
return objectToString(proxy);
}
throw new UnsupportedOperationException(method.getName());
}
public String objectClassName(Object obj) {
return obj.getClass().getName();
}
public int objectHashCode(Object obj) {
return System.identityHashCode(obj);
}
public boolean objectEquals(Object obj, Object other) {
return obj == other;
}
public String objectToString(Object obj) {
return objectClassName(obj) + '@' + Integer.toHexString(objectHashCode(obj));
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用创建代理
Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[]{interfaceType},
new ObjectInvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
if (method.equals(m)) {
return f.apply(args);
}
return super.invoke(proxy, method, args);
}
}
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1142 次 |
| 最近记录: |