5

I have written this test class and I am wondering why proxy object does have the same hashCode like original object. Does anyone know why?

public class Main {

public static void main(String[] args) {
    final Service realSubject = new Subject_A();
    final Service proxySubject = ProxyGenerator.makeProxy(Service.class, realSubject);
    final String hello = proxySubject.work("Hello");
    System.out.println("hello = " + hello);
    System.out.println("\n");
    System.out.println("realSubject: " + realSubject);
    System.out.println("proxySubject: " + proxySubject);
}
}

Thats an sample output:

in Subject_A#work: str = Hello
hello = Hello_DONE


realSubject: at.me.proxy.Subject_A@4f4a7090
proxySubject: at.me.proxy.Subject_A@4f4a7090
quma
  • 5,233
  • 26
  • 80
  • 146
  • 2
    You don't call `.hashCode()` in your code, so I fail to see what answer you expect. Sample output please? – fge Aug 24 '16 at 08:01
  • What is `Service`, `Subject_A` and `ProxyGenerator`? Are these from some library or you wrote them? – Codebender Aug 24 '16 at 08:06
  • 1
    Possible duplicate of [What issues should be considered when overriding equals and hashCode in Java?](http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java) – Raedwald Aug 24 '16 at 08:43
  • If it delegates equals it must delegate hashCode. – Raedwald Aug 24 '16 at 08:44

1 Answers1

3

Proxies are used to indirectly access underlying object and as far as client code is concerned the existence of proxy should be hidden.

Typically this pattern is used in frameworks such as spring and hibernate to decorate your objects with transaction or security capabilities. Given the above, it is only natural that the proxy object has same output for hashcode(), equals() and toString() as the underlying object.

Edit

Update according to corrections from @Holger

First of all, what you observed is same output for toString() call, not hashcode(). The implementation of equals() via proxies is a bit more subtle than at first glance. In typical implementation of equals(), the property of symmetry would be violated according to equals contract:

for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.

and there you have

// works since you delegate same instance of wrapped class to underyling object
proxy.equals(wrapped); // true

but

wrapped.equals(proxy); // false

due to:

 // proxy class != wrapped class 
 if (this.getClass() != obj.getClass()) {
        return false;
 }

As @Holger suggests, two proxies wrapping same underlying instance, could be equal without violation of symmetry.

An option to make proxy equal to wrapped instance and vice versa could be to implement equals via interface members(getters) for state that comprises object equality and compare classes against this interface. Since both proxy and underlying object conform to this interface they would be equal.

John
  • 5,189
  • 2
  • 38
  • 62
  • 1
    I have to object the idea of delegating `equals` as the result would violate the symmetry contract; the proxy would claim to be equal to the original object whereas the original object will usually not be equal to the proxy. But you point into the right direction: what we see here, is the delegation of `toString()` in action, producing the same output for the original object and the proxy, but in this code there’s no proof that `hashCode` will be delegated as well. – Holger Aug 25 '16 at 08:58
  • @Holger i might have misinterpreted: *An invocation of the hashCode, equals, or toString methods declared in java.lang.Object on a proxy instance will be encoded and dispatched to the invocation handler's invoke method in the same manner as interface method invocations are encoded and dispatched, as described above* from[docs]: https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html . It seems to me however that `equals()`, `hashcode()` and `toString()` are treated in the same way. – John Aug 25 '16 at 09:37
  • It’s correct, that they all are delegated to the `InvocationHandler`, but it’s that handler’s decision, how to process them. And letting the handler directly delegate an `equals` call to another object, is not a good idea. But you can, e.g. implement it in a way that two proxies wrapping the same object are equal. That would conform to the contract. – Holger Aug 25 '16 at 09:59