Java 使用JDK动态代理实现equals()

Java 使用JDK动态代理实现equals(),java,proxy,equals,dynamic-proxy,Java,Proxy,Equals,Dynamic Proxy,有史以来第一次,我必须使用标准JDK动态代理实现自己的代理类。它工作得相当好,除了一个细节:equals(…)方法 假设我们有这样一个简单的接口,我们想代理它: public interface MyInterface { public String getID(); public void setID(String id); } 。。。我们的实现如下所示(带有生成的hashCode()和等于的标准Java Bean): 问题是,当我创建代理时,equals(…)方法不再是对称

有史以来第一次,我必须使用标准JDK动态代理实现自己的代理类。它工作得相当好,除了一个细节:
equals(…)
方法

假设我们有这样一个简单的接口,我们想代理它:

public interface MyInterface {
    public String getID();
    public void setID(String id);
}
。。。我们的实现如下所示(带有生成的
hashCode()
等于
的标准Java Bean):

问题是,当我创建代理时,
equals(…)
方法不再是对称的:

original.equals(original); // true
proxy.equals(original);    // true, as the proxy forwards the call to the wrapped object
original.equals(proxy);    // false
proxy.equals(proxy);       // false
这也将在中讨论


我的问题是:如果我想让所有四个“equals”案例都提供
true
,那么最好的方法是什么(即最安全和最少干扰)?

这里有一个equals()的可能替代方案


此代码使用getID()而不是直接访问字段。到目前为止,它运行良好。

您将找到一个可行的解决方案。但有一个巨大的问题:

要相互比较的两个对象都必须知道代理包装

JAVA在技术环境中做到了这一点,即代理的处理与其他对象相同。但是

我在这个问题上的个人观点是:JAVA应该引入对代理的内置支持,一旦调用hashcode和equals,代理就可以在内部展开

代理应该对“正常”实现透明。你不应该为你是否有代理或原件而烦恼。但是JAVA这样做是错误的

一种可能性是让两个对象都知道代理包装,并用equals/hashcode处理它。但这会给原始类带来它不应该有的依赖项

另一种可能性是,如果不需要代理行为,则展开代理,并使用真实对象。在创建代理的上下文中,应该有如下映射:

Map<Proxy, Original> map;
Map;
您不应该到处传递JAVA代理。每个对象都必须知道,代理是传入的,因为它们可以将它们存储在激活equals和hashcode的Set实现中。一旦传递JAVA代理,使用具有这种依赖性的类就会造成污染

Java代理应该尽可能地隔离。生成Java代理的类应该是唯一使用它们的类


另一种(更常见的)可能性是使用标准代理模式,而不使用任何JAVA代理。但是在这里,你必须考虑在HASCOD/EQUALS中的代理包装,如果你将代理对象传递出去。

你必须在接口的成员方法方面实现你的接口实现的<>代码>均衡器< /代码>方法。查看
List#equals(Object)
是如何实现的(在javadoc中是如何描述的)。
public final boolean equals(final Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (! (obj instanceof MyInterface)) // neither a Proxy nor a MyImplementation
    return false;

    MyInterface other = (MyInterface) obj;
    if (this.getID() == null) {
       if (other.getID() != null) {
               return false;
       }
    } else if (!this.getID().equals(other.getID())) {
      return false;
    }
    return true;
}
Map<Proxy, Original> map;