• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Hash code consistency across multiple implementations.

 
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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().
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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?
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 1078
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Cool. I'm sleeping better already.....................................
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I just figured having asked the question I might explain what I did. Thanks for the help.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic