jQuery in Action, 2nd edition*
The moose likes Java in General and the fly likes Hash code consistency across multiple implementations. Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Hash code consistency across multiple implementations." Watch "Hash code consistency across multiple implementations." New topic
Author

Hash code consistency across multiple implementations.

Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Writing equals() and hashCode() implementations for a concrete or abstract class is pretty easy, but what do you do when an interface gets involved? As an example, let's say I have an Address interface and every Address has five attributes: street address, city, region, postal code and country.




A simple abstract implementation.



Now how would I approach making sure this is consistent with other implementations of Address? I'd be comfortable with just specifying in Address what equals() must fulfill (i.e. each attribute must be equal to the other using equals()) but what about the hash code? If they use a different algorithm, or the same algorithm with a different starting value or multiplier it will come out differently even if they both return true from equals().
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
There's a pretty good case for saying instances of two different classes should never be equals(). How different could two concrete Address classes be and still be equal?


A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
I don't have an answer to that. I suppose it's just me being over zealous in wanting to allow someone to create a different implementation that could still be the same. Suppose later someone needed a mutable address and created a MutableAddress implementation because AbstractAddress is immutable. If they still have the same street, city, region, postal code and country they're equal, yet if they have different hash code algorithms they won't work with a hash based collection.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Well, it's possible to allow subclasses to be equal to other subclasses, but it's usually inadvisable as the process is somewhat error-prone and likely to lead to confusing results. Generally in order to do this, you would need to require that all subclasses use effectively the same implementation of equals() and hashCode(). By "effectively the same" I mean that it would be preferable if they all inherited the exact same implementation from a single base class, which declares those two methods to be final. In some cases you might be tempted to make this base implementation nonfinal in order to allow subclasses to make implementations which are more efficient for that particular implementation. However the results of such methods are obligated to be the same as the base implementation results, or you will violate the base contract of equals() and/or hashCode().

As an example of a data type which allows different subtypes to evaluate as equal to each other, check out java.util.List. Since this is an interface, they can't provide a final implementation of equals() and hashCode() (and they decline to make the implementations in AbstractList final, thought they probably should have). However the APIs for these two methods in List do spell out fairly exact rules which all subtypes are required to follow, or lead to very confusing results.

Also, regarding your example of two Address types which are identical except that one is mutable while the other is immutable - personally I feel there is no good reason to use equals() or hashCode() on a mutable object if an immutable version is available. Mutable objects make lousy keys in Maps. Or rather, it's a horrible idea to ever change their values after they've been inserted into a Map. And so if an immutable version is available, why not use it? Much better I think. That, in my opinion, is why they didn't override equals() and hashCode() in StringBuffer. Why bother? Anyone wanting to evaluate equality of such objects is better off using immutable Strings instead. Not everyone agrees with this opinion of course. But still, the importance of having equivalent equals() implementations for mutable and immutable versions of what is otherwise the same datatype is... limited, at best. In my opinion.


"I'm not back." - Bill Harding, Twister
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
Maybe an equivalentAddress method would be in order. Or an AddressComparator class that could compare the address portion of different implementations. With either of those you wouldn't risk confusing the equals() hashcode() and compareTo() on the implementation classes.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
I just marked the equals() and hashCode() methods in the abstract class as final. If somebody wants to compare addresses of different implementations later they can use a Comparator or something akin to one.
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
Cool. I'm sleeping better already.....................................
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
I just figured having asked the question I might explain what I did. Thanks for the help.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Hash code consistency across multiple implementations.
 
Similar Threads
hashCode() & equals() method test
Canadian Post Codes as Base 26 calculations
Override equals and hashCode
Overriding equals() and hashCode() methods
Interfaces and abstract classes