Google Guava / Equivalence / different equals() and hashCode() method implementations - java

I want to be able to switch between two equals-Implementations, but I'm not sure if the Equivalence class of Google Guava maybe provides this functionality. Let's say I have two equals methods equalsContent() and equalsKeys() or something like that I somehow want to delegate the equals method to one of the two private methods (and the same for the two hashCode methods).
Well, I'm somehow not sure what the usage of the Equivalence abstract class and the Equivalences class (static methods) is.
Besides, how would you implement the desired properties described above? I could use another method which simply sets a flag or an enum to the value and implement the two equals and hash methods inside an enum with two abstract methods (equals(), hashCode()) and simply call enum.equals() or enum.hashCode() in the equals() and hashCode() method. What do you think?

I think the enum approach would make sense from an object-oriented point of view, but it's dangerous. It could break the equals() and hashCode() contract (reflexivity, symmetry, and transitivity). For example, inserting an instance that uses the first equivalence strategy and an instance that uses the second equivalence strategy in the same Set would cause problems.
If you want different equivalence relationships, you should keep those out of your class. Equivalence lets you do just that: you extract the equivalence logic (equals() / hashCode()) by implementing Equivalence and overriding the doHash() and doEquivalent() methods.
Then, when you want to use a Collection based on one equivalence or the other, you use Equivalence.wrap(). For example, you could emulate an IdentityHashSet by doing:
Set<Equivalence.Wrapper<String>> identityHashSet = Sets.newHashSet();
String a1 = "a";
String a2 = new String("a");
String b = "b";
identityHashSet.add(Equivalences.identity().wrap(a1));
identityHashSet.add(Equivalences.identity().wrap(a2));
identityHashSet.add(Equivalences.identity().wrap(a3));
// identityHashSet contains "a", "a", and "b"
// a standard HashSet would only contain "a" and "b"
// while a1 and a2 are equal according to String.equals(), they are different instances.
Of course, you could use ForwardingSet to automate the wrapping / unwrapping of your elements.
There is more info in this Guava issue.

Related

Dilemma with hashCode() - Java

I have the following code,
Object testA = new Object();
Object testB = testA;
System.out.println("A:"+testA.hashCode())
System.out.println("B:"+testB.hashCode())
Per the above, I get the same hashcode for the two objects. I understand that testB is assigned testA and so it could have the same hashcode, however there should be a way to uniquely identify the difference in both these objects right?
Please let me know if there is something obvious that am missing!
however there should be a way to uniquely identify the difference in both these objects right?
There is no difference, since there are no two objects. There is just one object referred by two variables.
In theory, two different objects may have the same hashCode. You can tell them apart by using equals or by using ==. If you don't override equals, it behaves as == by default.
The hashCode function has to be compatible with the equals method in the sense that hashCode has to return the same value for 2 objects that are equal. In this case, they are not only "equal" (according to the equals method), but even the same object (which implies that they are equal).
Besides, independently of what the specification demands, it would impossible for the 2 calls to hashCode to return different values because both variables are actually referencing the same object. There is no way to distinguish testA and testB (apart from the variable name, of course).
You create a new object testA but then assign testB to testA, which assigns the same memory space for both of the objects. This is why its returning the same HashCode.

Java: Is it OK to implement hashCode and equals for a third-party class?

Assume we have the following class:
public class SingleElementRefType
{
protected JAXBElement<SequenceType> sequence;
// ...
}
It contains the sequence field of type JAXBElement.
JAXBElement is a third-party class (standard API, actually), which is in essence a pure value class, but it for some reason does not implement hashCode and equals methods.
From my point of view, these methods are absolutely reasonable there.
I would like to implement equals and hashCode methods for SingleElementRefType as well as SequenceType so that I could do a deep comparison of this values. But JAXBElement stands in the way.
Since I can't extend JAXBElement, my idea was to integrate hashCode and equals into the aggregating class (SingleElementRefType here):
JAXBElement<SequenceType> theSequence;
theSequence = this.getSequence();
final QName theSequenceName = theSequence.getName();
currentHashCode = ((currentHashCode* 37) +
((theSequenceName!= null)?theSequenceName.hashCode(): 0));
final Object theSequenceValue = theSequence.getValue();
currentHashCode = ((currentHashCode* 37) +
((theSequenceValue!= null)?theSequenceValue.hashCode(): 0));
But then I had second thoughts if I'm not breaking some convention or rule here.
Are there any dangers of implementing hashCode and equals for third-party classes in my aggregating classes?
Update: for certain reasons my code may not have further runtime dependencies. So I can't use Guava or commons-lang here.
It is perfectly reasonable to override the hashCode and equals method of your model class. While overriding them, java specifies a list of contracts to be followed.
For equals,
reflexive [x.equals(x) = true]
symmetric[x.equals(y)=true, then (y.equals(x)==true) ]
transitive [x.equals(y)==true && y.equals(z)==true, then x.equals(z)==true]
consistent
‘non-nullity’ [x.equals(null)==false]
For hashCode,
consistency : return same integer for the same object
if (o1.equals(o2), then o1.hashcode == o2.hashcode)
not viceversa
This answer can provide you insight into best practices to be followed while overriding hashCode().
And for overriding equals follow these practices :
Use == to check if the argument is a reference to this object
Use instanceof operator to check if the argument has the correct type
Cast the argument to the correct type
For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object
A way you can make sure that your overridden hashCode and equals method are effectively following the contracts will be to test them using Junits.
Need of overriding hashCode and equals will be more evident when, at some point of time, have to use your model class in a hash based collection, say a hashmap or hashset.

Why Java does not support Equality comparison on the Lines of Comparator?

Java provides way to define comparison of object outside scope Object using Comparator.
Now my questions is why java does not allow do same for equals() and hashcode().
Now each collection contains() method can easily use this external equality provider to check objects are equal.
Guava has the Equivalence class, which does pretty much what you are asking for.
You can even wrap an Object in an Equivalence to decorate an Object with a better hashCode() equals() implementation (e.g. if you want to use an Object with a bad equals() hashCode() as a Map key but don't have access to the sources)
Here's an example: arrays don't have proper implementations of equals() and hashCode(), but here's an Equivalence for char arrays:
private static final Equivalence<char[]> CHAR_ARRAY_EQUIV = new Equivalence<char[]>(){
#Override
protected boolean doEquivalent(char[] a, char[] b) {
return Arrays.equals(a, b);
}
#Override
protected int doHash(char[] chars) {
return Arrays.hashCode(chars);
}
};
Sample code:
final char[] first ={'a','b'};
final char[] second ={'a','b'};
Assert.assertFalse(first.equals(second));
Assert.assertFalse(first.hashCode() == second.hashCode());
final Wrapper<char[]> firstWrapped = CHAR_ARRAY_EQUIV.wrap(first);
final Wrapper<char[]> secondWrapped = CHAR_ARRAY_EQUIV.wrap(second);
Assert.assertTrue(firstWrapped.equals(secondWrapped));
Assert.assertTrue(firstWrapped.hashCode() == secondWrapped.hashCode());
Comparator interface is used to compare objects while sorting collections, and its compare() method returns an "int", means, comparision ends with an int value, which can be used to indicate object's place in a sorted collection.
contains() calls equals() method for each instance in a collection in order to find out whether two instances are equal according to equals- contract.
equals and hashCode are concepts that don't change for a given Object. Only the implementor knows what values should be used according to the rules for these methods. Once he decided about those they define the identy of the object and thus should not be changed ever.
Comparasion on the other hand can be highly dependent on the context. You can define a "natural" order by implementing Comparable. But this can't change for different contexts. Say you have a list of Contacts that can be sorted by last name, first name, zip code, city... You can easily do this by providing separate Comparators (or a parametrized Comparator). But it is not inherent to the object itself so it should be a class of its own (it could be implemented as static inner class, depending on your code conventions).

questions regarding hashcode

I have some doubts regarding equals and hashcode. What I have understood previously is, we need to override the hashcode() and equals() method in the object class if that class is supposed to add to the collection class or Map class. Please see the below example. I did not override the hashcode and equals method. Still I get the desired result what I want. One thing i understood that, If I want to compare two object we need to override the equals method. But in this example I am not comparing two objects, rather I am adding objects to collection or Map without overriding the hashcode and equals. Could anyone explain why do we need to override the hashcode and when?
package equalshashcode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EqualsAndHashCode {
public static void main(String[] args) {
Student student1 = new Student("A");
Student student2 = new Student("B");
List<Student> studentList = new ArrayList<Student>();
Map<Integer,Student> studentMap = new HashMap<Integer,Student>();
studentMap.put(1, student1);
studentMap.put(2, student2);
studentList.add(student1);
studentList.add(student2);
System.out.println("Student HashMap:: "+studentMap.get(1));
System.out.println("Before removing::"+studentList);
System.out.println(studentList.remove(student1));//true success
System.out.println("After removing::"+studentList);
}
}
class Student{
String name;
public Student(String pName){
this.name = pName ;
}
public String getName(){
return this.name ;
}
}
You don't always need to implement equals() and hashCode() to add elements into a collection.
For a List (such as you studentList, which is an ArrayList instance) it doesn't matter for most actions.
The only places where you need equals() and hashCode() is where "equality" of objects is relevant. And even in those places the default implementation might even be sufficient.
Equality matters in several cases, for example:
A Set can't contain two objects that are equal to each other
The key of a Map must have a correct equals() implementation to be retrievable (and based on the concrete Map implementation, that might imply that hashCode() has to be correctly implemented as well).
Some methods on a "normal" List also need equality. For example contains(), indexOf() and remove(Object) need correctly implemented equals()/hashCode()
Custom equals and hashCode methods are generally used for determining actual equality. If you rely on the default equals method, this will look for the same instance in memory. For example customObj1.equals(customObj2) will return false if there's no custom equals method and the two objects are separate (but otherwise equal) instances. The idea of a custom equals method is to make that same example return true if they are actually equal. A Map will then be able to use this to match the key object passed in a get(key) request to find the value without needing to have the correct instance of the key (a HashMap actually uses hashCode to do this).
The most obvious example of this being useful is for Strings, so that you can do myMap.get("key") and get the correct value, even if your key instance isn't the same as the one stored in the Map (String implements equals and hashCode for you). In general I would recommend using these Java built-in equals and hashCode methods to construct your own. For example if your object has a natural ID, such as say userName, your equals can use the String version of this to complete your own equals (you can obviously compare multiple fields):
public boolean equals(Object o) {
if (o instanceof MyObj) {
return userName.equals(((MyObj) o).userName));
}
return false;
}
As such, if you'll only be working with a single Thread, or otherwise limited variables, you'll likely never need to implement these methods, but there are certainly times when it pays off to know them.
Collection classes will work perfectly well with objects that have the default equals/hashCode implementations - there is no need to add your own for this reason.
Custom equals/hashCode methods are easy to get wrong, and unless you have a good reason to roll your own you should just stick with the ones that you get for free with java.lang.Object.
The most common reason for creating your own version of these methods is if you want to treat two separate instances of the same class as being equal. For example, if you have an Account class and you want two instances of Account which have the same accountNumber property to be regarded as equal, because they represent the same real-world account. In this case you would base your equals method on the value of accountNumber alone, and since you now have a custom equals method you need to provide a suitable implementation of hashCode as well, in order to fulfil the equals/hashCode contract.

How to override the (final) equals method in java enums?

I have a problem with overriding the equals method in an Enum to make it compatible with other classes.
The Enum implements an interface and the idea is that all implementations of this interface can be tested for equality, regardless of their type. For Example:
public interface Group {
public Point[] getCoordinates();
}
public enum BasicGroups implements Group {
a,b,c; // simplified, they actually have constructors
// + fields and methods
}
public class OtherGroup implements Group {
// fields and methods
}
If both a BasicGroup and an OtherGroup have the same coordinates (in arbitrary order) then the equals method should return true.
No problem when performing myOtherGroup.equals(BasicGroup.a) but since the equals method in Enums is final, I can't override them.
Is there some way to work around this? Like when testing on another BasicGroup the default equals method (reference equality) is used and when testing other classes my own implementation is used. And how do I make sure that java doesn't use the wrong one when I do BasicGroup.a.equals(myOtherGroup)?
You can NOT #Override a final method (§8.4.3.3); this much is clear. enum types (§8.9) are treated very specially in Java, which is why the equals is final (also clone, hashCode, etc.) It's simply not possible to #Override the equals method of an enum, nor would you really want to in a more typical usage scenario.
HOWEVER, looking at the big picture, it looks like you are trying to follow the pattern recommended in Effective Java 2nd Edition, Item 34: Emulate extensible enums with interfaces (see the language guide for more information about enum):
You have defined this interface (now documented explicitly for expected equals behavior):
public interface Group implements Group {
public Point[] getCoordinates();
/*
* Compares the specified object with this Group for equality. Returns true
* if and only if the specified object is also a Group with exactly the same
* coordinates
*/
#Override public boolean equals(Object o);
}
It is perfectly acceptable for an interface to define how equals method for implementors should behave, of course. This is exactly the case with, e.g. List.equals. An empty LinkedList is equals to an empty ArrayList and vice versa, because that's what the interface mandates.
In your case, you've chosen to implement some Group as enum. Unfortunately you now can't implement equals as per the specification, since it's final and you can't #Override it. However, since the objective is to comply to the Group type, you can use decorator pattern by having a ForwardingGroup as follows:
public class ForwardingGroup implements Group {
final Group delegate;
public ForwardingGroup(Group delegate) { this.delegate = delegate; }
#Override public Point[] getCoordinates() {
return delegate.getCoordinates();
}
#Override public boolean equals(Object o) {
return ....; // insert your equals logic here!
}
}
Now, instead of using your enum constants directly as Group, you wrap them in an instance of a ForwardingGroup. Now this Group object will have the desired equals behavior, as specified by the interface.
That is, instead of:
// before: using enum directly, equals doesn't behave as expected
Group g = BasicGroup.A;
You now have something like:
// after: using decorated enum constants for proper equals behavior
Group g = new ForwardingGroup(BasicGroup.A);
Additional notes
The fact that enum BasicGroups implements Group, even though it does not itself follow the specification of Group.equals, should be very clearly documented. Users must be warned that constants must be e.g. wrapped inside a ForwardingGroup for proper equals behavior.
Note also that you can cache instances of ForwardingGroup, one for each enum constants. This will help reduce the number of objects created. As per Effective Java 2nd Edition, Item 1: Consider static factory methods instead of constructors, you may consider having ForwardingGroup define a static getInstance(Group g) method instead of a constructor, allowing it to return cached instances.
I'm assuming that Group is an immutable type (Effective Java 2nd Edition, Item 15: Minimize mutability), or else you probably shouldn't implement it with enum in the first place. Given that, consider Effective Java 2nd Edition, Item 25: Prefer lists to arrays. You may choose to have getCoordinates() return a List<Point> instead of Point[]. You can use Collections.unmodifiableList (another decorator!), which will make the returned List immutable. By contrast, since arrays are mutable, you'd be forced to perform defensive copying when returning a Point[].
See also
Using the decorator design pattern for a hierarchy of classes
when do we need Decorator Pattern?
com.google.common.collect.ForwardingObject
What is the best way to cache and reuse immutable singleton objects in Java?
It's not possible to do this in Java. (The sole purpose of the final keyword when it comes to methods, is to prevent overriding!)
equals and a few other methods on Enums are final, so you can't change the behavior of them. (And you shouldn't :) Here is my answer to a related question:
The intuition of clients that deal with enum constants is that two constants are equal if and only if they are the same constant. Thus any other implementation than return this == other would be counterintuitive and error prone.
Same reasoning applies to hashCode(), clone(), compareTo(Object), name(), ordinal(), and getDeclaringClass().
The JLS does not motivate the choice of making it final, but mentions equals in the context of enums here. Snippet:
The equals method in Enum is a final method that merely invokes super.equals on its argument and returns the result, thus performing an identity comparison.
You can solve this by calling your method hasSameCoordinatesAs, or similar, rather than equals.
equals for enums is defined in the language specification, so you can't hope to redefine it.
Equality is quite elusive. Different contexts require different equality relations. By having equals() method on Object, Java imposes an "intrinsic" equality, and APIs, like Set, depend on it.
Meanwhile, ordering isn't considered "intrinsic", two objects can be ordered differently in different contexts, and APIs usually allow us to supply a comprator, i.e., a custom ordering relation.
This is interesting. In math terms, equality, like order, is just a relation, and there can be different equality relations. The concept of "intrinsic equality" isn't holy.
so let's have an Equal-ator too, and change APIs to accept custom equality relations:
interface Equalator
boolean equal(a, b)
public HashSet( Equalator equalator )
Actually, we can build wrappers around current collection APIs, and add this feature of new equality.
This might answer your question. Why do you have a dependency on equals() in the first place? And can you remove that, and depend instead on "equalator"? Then you are set.

Categories