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.
Related
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.
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).
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.
I'ver been wondering how to best implement equals() for a family of classes that all implement the same interface (and the client is supposed to work only with said interface and never to know about implementing classes).
I haven't cooked up my own concrete example, but there are two examples in the JDK - java.lang.Number and java.lang.CharSequence that illustrate the decision:
boolean b1 = new Byte(0).equals( new Integer(0) ) );
or with CharSequence
boolean b2 = "".equals(new StringBuilder());
Would you ideally want those to evaluate to true or not? Both types do implement the same datatype interface, and as a client working with Numbers (resp. CharSequences) instances I would have an easier life if equals would compare the interface types instead of the implementing types.
Now this is not an ideal example, as the JDK exposes the implementing types to the public, but suppose we had not have to uphold compatibility with what is already there - from a designers point of view: Should equals check against the interface or is it better the way it is, checking against the implementation?
Note: I understand that checking for equality against an interface can be very hard to actually implement properly in practice and its made even more tricky since equal interfaces also need to return the same hashCode().
But those are only obstacles in implementation, take for example CharSequence, although the interface is pretty small, everything required for equality checks is present whithout revealing the internal structure of the implementation (so it is principally possible to implement properly, even without knowing about future implementations in advance).
But I am more interested in the design aspect, not on how to actually implement it. I wouldn't decide solely based on how hard something is to implement.
Define an abstract class that implements your interface and defines final equals()/hashCode() methods and have your customers extend that instead:
public interface Somethingable {
public void something();
}
public abstract class AbstractSomethingable implements Somethingable {
public final boolean equals(Object obj) {
// your consistent implementation
}
public final int hashCode() {
// your consistent implementation
}
}
Notice that by making your class abstract, you can implements the interface without defining the interface's methods.
Your customers still have to implement the something() method, but all their instances will use your code for equals()/hashCode() (because you've made those methods final).
The difference to your customers is:
Using the extends keyword instead of the implements keyword (minor)
Not being able to extend some other class of their choosing to use your API (could be minor, could be major - if it's acceptable then go for it)
I would normally assume that "similar" objects would not be equal - for example I wouldn't expect the Integer(1) would pass equals(Long(1)) . I can imagine situations where that would be reasonable, but as the jdk needs to be a general-purpose API you wouldn't be able to make the assumption that that would always be the correct thing to do.
If you've got some sort of custom objects where it's reasonable, I think it's perfectly fine to implement an expanded definition of equals if you
are sure that you don't have some edge cases where you really do need the more specific equality (i.e. that would require the identical classes)
document it very clearly
make sure that hashcode behaves consistently with your new equals.
For what it's worth, I'd probably do an implementation-specific equals implementation (side note - don't forget to implement hashCode...). Interface-level equals() puts a pretty heavy burden on implementers of the interface - who might or might not be aware of the special requirement.
Often, implementation-level works fine as your client only deals with one implementation (i.e. MyNumberProcessor can works on any Number, but practically one instance of it would only have to handle Long and maybe another only Double). Generics are a great way of making sure that happens.
In the rare case where it does matter, I would probably design the client to allow injection of a Comparator or - when not available - encapsulate my Numbers into a VarTypeNumber.
I'd try to add another equals Method to my interface. How about that:
assertFalse(new Integer(0).equals(new Byte(0))); // pass
assertTrue(new Integer(0).valueEquals(new Byte(0))); // hypothetical pass
This does not produce unexpected behaviour (different types equal) but keeps the possibility open to check for equal values.
There's a somewhat related topic in effective java where equals with instanceof and getClass is discussed. Can't remember the item number, though.
I would consider any implementation of equals that returns true for two objects that do not have the same concrete type to be extremely 'surprising' behavior. If you're operating inside a box where you know at compile time every possible implementor of the interface, you can fabricate equals that make sense with only interface methods, but that's not a reality for API/framework code.
You can't even be sure that nobody's going to write an implementation of the interface that mutates its internal state when you call the methods that you used to implement equals! Talk about confusing, an equals check that returns true and invalidates itself in the process?
--
This is what I understood to be the question as far as 'checking equality against the interface':
public interface Car {
int speedKMH();
String directionCardinal();
}
public class BoringCorrolla implements Car {
private int speed;
private String directionCardinal;
public int speedKMH() { return speed; }
public String directionCardinal() { return directionCardinal; }
#Override
public boolean equals(Object obj) {
if (obj isntanceof Car) {
Car other = (Car) obj;
return (other.speedKMH() == speedKMH() && other.directionCardinal().equals(directionCardinal());
}
}
}
public class CRAZYTAXI implements Car, RandomCar {
public int speedKMH() { return randomSpeed(); }
public String directionCardinal() { return randomDirection();}
}
It is possible to define equality among different classes.
In your case, the exact equality algorithm must be specified by the interface, so any class implementing the interface must abide by it. Better yet, since the algorithm depends only on information exposed by the inferface, just implement it already, so subclasses can simply borrow it.
interface Foo
class Util
static int hashCode(Foo foo){ ... }
static boolean equal(Foo a, Foo b){ ... }
static boolean equal(Foo a, Object b)
return (b instanceof Foo) && equal(a, (Foo)b);
class FooX implements Foo
int hashCode()
return Util.hashCode(this);
boolean equals(Object that)
return Util.equal(this, that);
I have an interface and two objects implementing that interface, massively simplied;
public interface MyInterface {
public int getId();
public int getName();
...
}
public class A implements MyInterface {
...
}
public class B implements MyInterface {
...
}
We are migrating from using one implementation to the other but I need to check that the objects of type B that are generated are equivalent to those of type A. Specifically I mean that for all of the interface methods an object of Type A and Type B will return the same value (I'm just checking my code for generating this objects is correct).
How would you go about this?
Map<String, MyInterface> oldGeneratedObjects = getOldGeneratedObjects();
Map<String, MyInterface> newGeneratedObjects = getNewGeneratedObjects();
// TODO: Establish that for each Key the Values in the two maps return equivalent values.
I'm looking for good coding practices and style here. I appreciate that I could just iterate through one key set pulling out both objects which should be equivalent and then just call all the methods and compare, I'm just thinking there may be a cleaner, more extensible way and I'm interested to learn what options there might be.
Would it be appropriate / possible / advised to override equals or implement Comparable?
Thanks in advance,
Gavin
I would implement a custom version of equals in the test class, not inside any of those implementation classes (since it would clash with the regular equals contract). Something like:
boolean equals(A a, B b) ...
I understand that this check would be required only during the migration period, so the normal equals methods of each implementation should not be affected by this. Namely, A.equals should only return true for an equal instance of A, and should always return false for an instance of B. And vice versa.
Once the migration is over, you no longer need class A neither the tester class, and you can continue using class B without needing to touch its implementation.
Note that if MyInterface (or A and B) extends Comparable, you should also test that the implementations in A and B are equivalent.
(And you surely know that if you implement equals you must also implement hashCode.)