The basic question here is "How can you determine if two objects are equal to each other?"
This is a simple question for simple objects. However, it becomes increasingly difficult with even slightly more complex objects.
As stated in the original question:
The only unique thing about the object is the the map myMap which gets populated later in the lifecycle.
Given two instances of the type MyObject
, the member variables myMap
must be compared with each other. This map is of type Map<String, String>
. A few questions immediately come to mind:
- How do the keys & values define equality?
- (does a key=value pair need to be compared as a unit?)
- (or should only the values be compared to each other?)
- How does the order of the keys in the map affect equality?
- (should keys in the list be sorted, so that A-B-C is equivalent to B-C-A?)
- (or does 1-2-3 mean something different than 3-2-1?)
- Does upper/lower case make any different to the equality of the values?
- Will these objects ever be stored in some kind of Java HashSet or Java TreeSet?
- (do you need to store the same object several times in the same collection?)
- (or should objects with equal hashcodes only be stored once?)
- Will these objects ever require sorting as part of a list or Java Collection?
- How should the comparison function arrange non-equal objects in a list?
- (how should key order determine if an object will come earlier or later in a list?)
- (how should values determine order, especially if several values are different?)
Answers to each of these questions will vary between applications. In order to keep this applicable to a general audience, the following assumptions are being made:
- To maintain a deterministic comparison, keys will be sorted
- Values will be considered to be case-sensitive
- Keys and values are inseparable, and will be compared as a unit
- The Map will be flattened into a single String, so results can be compared easily
The beauty of using equals()
, hashCode()
, and compareTo()
is that once hashCode()
is implemented properly, the other functions can be defined based on hashCode()
.
Considering all of that, we have the following implementation:
@Override
public boolean equals(final Object o)
{
if (o instanceof MyObject)
{
return (0 == this.compareTo(((MyObject) o)));
}
return false;
}
@Override
public int hashCode()
{
return getKeyValuePairs(this.myMap).hashCode();
}
// Return a negative integer, zero, or a positive integer
// if this object is less than, equal to, or greater than the other object
public int compareTo(final MyObject o)
{
return this.hashCode() - o.hashCode();
}
// The Map is flattened into a single String for comparison
private static String getKeyValuePairs(final Map<String, String> m)
{
final StringBuilder kvPairs = new StringBuilder();
final String kvSeparator = "=";
final String liSeparator = "^";
if (null != m)
{
final List<String> keys = new ArrayList<>(m.keySet());
Collections.sort(keys);
for (final String key : keys)
{
final String value = m.get(key);
kvPairs.append(liSeparator);
kvPairs.append(key);
kvPairs.append(kvSeparator);
kvPairs.append(null == value ? "" : value);
}
}
return 0 == kvPairs.length() ? "" : kvPairs.substring(liSeparator.length());
}
All the critical work is being done inside of hashCode()
. For sorting, the compareTo()
function only needs to return a negative/zero/positive number -- a simple hashCode()
diff. And the equals()
function only needs to return true/false -- a simple check that compareTo()
equals zero.
For further reading, there is a famous dialogue by Lewis Carroll on the foundations of logic, which touches on the basic question of equality:
https://en.wikipedia.org/wiki/What_the_Tortoise_Said_to_Achilles
And, in regard to even simple grammatical constructs, there is a fine example of two "equal" sentences at the start of chapter 6, "Pig and Pepper", from Alice in Wonderland:
The Fish-Footman began by producing from under his arm a great letter, and this he handed over to the other, saying, in a solemn tone, "For the Duchess. An invitation from the Queen to play croquet." The Frog-Footman repeated, in the same solemn tone, "From the Queen. An invitation for the Duchess to play croquet." Then they both bowed low and their curls got entangled together.