I'm trying to write some generic code to define class equality and hashcodes based on a list of fields. When writing my equals method, I was wondering if, based on Java convention, it should ever be possible for two object of different to be equal. Let me give some examples;
class A {
int foo;
}
class B {
int foo;
}
class C extends A {
int bar;
}
class D extends A {
void doStuff() { }
}
...
A a = new A(); a.foo = 1;
B b = new B(); b.foo = 1;
C c = new C(); c.foo = 1; c.bar = 2;
D d = new D(); d.foo = 1;
a.equals(b); //Should return false, obviously
a.equals(c);
c.equals(a); //These two must be the same result, so I'd assume it must be false, since c cant possible equal a
a.equals(d); //Now this one is where I'm stuck.
I see no reason that in the last example the two shouldn't be equal, but they do have different classes. Anyone know what convention dictates? And if they would be equal, how should an equals method handle that?
Edit: if anyone's interested in the code behind this question, see: https://gist.github.com/thomaswp/5816085 It's a little dirty but I'd welcome comments on the gist.
They could be, but it's typically very difficult to maintain the symmetric and transitive properties of equality in that case. At least while having a useful/intuitive definition of equality.
If you allow a subclass to consider itself equal to an instance of the superclass, then the superclass needs to consider itself equal to an instance of the subclass. Which means that you'll be encoding specific knowledge about the subclass (all possible subclasses?) in the superclass, and downcasting as needed, which isn't very clean.
Or, you do the comparison purely with fields contained in A, and don't override equals() at all. This fixes the above, but has the problem that two instances of C with different values of bar would be considered equal, which is probably not what you want.
Or, you override in C, and compare bar if the other object is an instance of C, but otherwise don't for an instance of A, you have another problem. c1.equals(c2) would be false, but c1.equals(a) would be true, as would c2.equals(a) and so a.equals(c2). This breaks transitivity (since c1 == a and a == c2 implies c1 == c2).
In summary, it's theoretically possible but you would have to cripple your equals implementation to do so. And besides, the runtime class is a property of an object just as much as bar is, so I'd expect objects with different concrete classes to be not equal to each other anyway.
First note: when you override .equals(), you absolutely MUST override .hashCode() as well, and obey the defined contract. This is no joke. If you do not obey THAT, you are doomed to encounter problems.
As to handling equality between different classes inheriting one another, if all these classes have a common member, this can be done as such:
#Override
public int hashCode()
{
return commonMember.hashCode();
}
#Override
public boolean equals(final Object o)
{
if (o == null)
return false;
if (this == o)
return true;
if (!(o instanceof BaseClass))
return false;
final BaseClass other = (BaseClass) o;
return commonMember.equals(other.commonMember); // etc -- to be completed
}
Also remember that you need to follow these rules in order to correctly implement the equals method.
Reflexive : Object must be equal to itself.
Symmetric : if a.equals(b) is true then b.equals(a) must be true.
Transitive : if a.equals(b) is true and b.equals(c) is true then c.equals(a) must be true.
Consistent : multiple invocation of equals() method must result same value until any of properties are modified. So if two objects are equals in Java they will remain equals until any of there property is modified.
Null comparison : comparing any object to null must be false and should not result in NullPointerException. For example a.equals(null) must be false, passing unknown object, which could be null, to equals in Java is is actually a Java coding best practice to avoid NullPointerException in Java.
As Andrzej Doyle rightly said, it becomes difficult to implement the Symetric and Transitive property when it's spread across multiple classes.
Object.equals() is required to be reflexive, symmetric, transitive, consistent across multiple invocations, and x.equals(null) must be false. There are no further requirements beyond that.
If equals() for a class you define does all of those things, then it's an acceptable equals() method. There is no answer to the question of how fine-grained it should be other than the one you provide yourself. You need to ask yourself: Which objects to I want to be equal?
Note, however, that you should have a good reason for making a.equals(b) true when a and b are instances of different classes, as that can make it tricky to implement a correct equals() in both classes.
This question seems to me to indicate a muddy architecture. In theory, if you want to implement .equals such that you compare only specific members of the two instances you can do this, but whether this is a good idea really depends on just what purpose these classes are intended to serve (and even then I think there are better approaches).
Are these objects, more or less, just intended to be nothing more than bags of data? If so, perhaps you should create a separate comparison class that determines whether the two objects are "equivalent enough" for the purposes you need, rather than force the objects themselves to care about some alien, unrelated class. I'd be concerned if my code were concerning itself with potentially unrelated objects just because I thought it might be a good idea for them to know about each other due to temporary convenience. Also, as Andrzej mentioned, it's very problematic for a parent class to know or care about specific implementation details of derived classes. I've seen first-hand how this causes problems both subtle and egregious.
Are the objects "doers" rather than data storage? Since your subclass D implements a method then this indicates that it's more than just a bag of data... and in this case, philosophically, I can't see how it would be a good idea to consider A and D equal based merely on a set of value fields. Compare the fields, yes. Consider them equal or equivalent? No. This sounds like a maintainability nightmare in the long haul.
Here's an example of what I think would be a better idea:
class A implements IFoo{
private int foo;
public int getFoo(){ return foo; }
}
class B implements IFoo{
private int foo;
public int getFoo(){ return foo; }
}
class CompareFoos{
public static boolean isEquivalent(IFoo a, IFoo b){
// compare here as needed and return result.
}
}
IFoo a = new A();
IFoo b = new B();
boolean result = CompareFoos.isEquivalent(a, b);
To some extent it depends on what you want the code to do. As long as you are clear what the equals method will compare then I don't see a problem necessarily. I think the problem really comes when you start making lots of sub-classes (e.g. Class E). There's a danger than that one of the sub-classes won't follow the contract so you could end up with
a.equals(e) --> true
e.equals(a) --> false
which would result in strange behaviour.
Personally I try to avoid equals comparing two different classes and returning true but I have done it a couple of times where the whole class hierarchy was under my control and final.
Consider this example -
abstract class Quadrilateral{
Quadrilateral(int l, int w){
length=l;
width=w;
}
private int length, width;
}
class Rectangle extends Quadrilateral{
Rectangle(int l, int w){super(l,w);}
}
class Square extends Quadrilateral{
Square(int l){super(l, l);}
}
Square s = new Square(3);
Rectangle r = new Rectangle(3,3);
r.equals(s);//This should be true because the rectangle and square are logically the same.
So yes, there are cases where two different classes can be equal. Though clearly this is not common.
No.
Set<Parent> p = new HashSet<>();
p.insert(new Parent(1));
p.insert(new Child(1));
Supposing those two instances are equals, does p contain a Child? Very unclear. More fun:
class Parent {
public int foo = 0;
void foo() {
foo = 1;
}
}
class Child extends Parent {
#Override
void foo() {
foo = 2;
}
}
Set<Parent> set = new HashSet<>();
for(Parent parent : set) {
parent.foo();
System.out.println(parent.foo); // 1 or 2?
}
I challenge you to know what p's element contains without spending more than 1 minute on the Javadoc pages for Set, HashSet, or equals.
The short answer is that in very limited cases (e.g. Integer and Long) it is OK for two objects of different classes to be equal, but it is so hard to pull off correctly that it is generally discouraged. It's hard enough to ensure that you create an equals() method that is Symmetric, Reflexive, and Transitive, but on top of that you should also:
create a hashCode() method that is consistent with equals()
create a compareTo() method that is consistent with equals()
further ensure that the compareTo() method is well behaved
Failure to do that can cause problems with using the objects in Sets, Trees, Hashes, and Sorted Lists.
There's a good article on the the topic of equals() based on part of Josh Bloch's book Effective Java but even that only covers equals(). The book goes into much greater detail, especially about how the problem becomes serious quickly once you start using the objects in collections.
It depends what you need, as #andrzeg said.
One additional thing. Do you want a.equals(d) to be true, but d.equals(a) to be false? when coding you will probably be using instanceof which may or may not be what you want.
I think that this question can be reduced to whether to use instanceof or getClass() in equals() implementation.
If D derives A and your inheritance hierarchy is right then indeed D IS A. It is logical to treat D as any other A and therefore you should be able to check D for equality as you would any other A.
Here is a link where Josh Bloch explains why he favors the instanceof approach.
http://www.artima.com/intv/bloch17.html
Related
I am facing a bizarre outcome in a java application (Spring batch job) after one of the internal custom dependencies -a library we have developed in my company- has been upgraded.
After the upgrade in the code two new different objects of the same type show to have the same hash code.
CustomObject oj1 = new CustomObject();
oj1.setId(1234L);
CustomObject oj2 = new CustomObject();
oj2.setId(9999L);
System.out.println(oj1); //Prints CustomObject#1
System.out.println(oj2); //Prints CustomObject#1
System.out.println(oj1.hashCode()); //Prints 1
System.out.println(oj2.hashCode()); //Prints 1
I noticed this issue after realizing that one of the unit test which has a HashSet variable was only adding the very first object and ignoring the rests. Obviously the hashSet is doing what is supposed to do but the objects are not supposed to be the same and are new instances with different Ids. I tested the same thing outside of the unit test within the application and still the same issue. As soon as I revert back to the old dependency code behaves normally and the above print statements show different numbers!
I am sure one of the dependencies is causing this issue abut I am not able to determine the root cause.
CustomObject is being pulled indirectly through that same dependency and does not have equals() and hashcode() implemented, it only has
private static final long serialVersionUID = 1L;
Looking at the source of CustomObject reveals this implementation
public class CustomObject extends BaseModel implements Serializable
and BaseModel has the equals and hashCode methods defined
import org.jvnet.jaxb2_commons.lang.*;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import java.io.Serializable;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "BaseModel")
#XmlSeeAlso({
CustomObject.class
})
public abstract class BaseModel implements Serializable, Equals2, HashCode2
{
private final static long serialVersionUID = 1L;
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy2 strategy) {
if ((object == null)||(this.getClass()!= object.getClass())) {
return false;
}
if (this == object) {
return true;
}
return true;
}
public boolean equals(Object object) {
final EqualsStrategy2 strategy = JAXBEqualsStrategy.INSTANCE;
return equals(null, null, object, strategy);
}
public int hashCode(ObjectLocator locator, HashCodeStrategy2 strategy) {
int currentHashCode = 1;
return currentHashCode;
}
public int hashCode() {
final HashCodeStrategy2 strategy = JAXBHashCodeStrategy.INSTANCE;
return this.hashCode(null, strategy);
}
}
Thank you in advance.
Clearly something has changed in a base class, and you will just have to find it and fix it, or else implement hashCode() and equals() acceptably in this class.
Somebody somewhere has implemented hashCode() to return 1, which is idiotic. They would have been better off not to implement it at all. And it's not hard to find. Just look at the Javadoc for CustomObject and see where it inherits hashCode() from.
I think you have already realized what the answer to your question is, but the code that you added in your update makes it clear:
Your CustomClass extends the BaseClass.
The BaseClass overrides Object::hashCode()
The override in the version of BaseClass that you showed us will always return 1. It is calling a hashCode(ObjectLocator, HashCodeStrategy2) method with a specific strategy, but the implementation of that method simply ignores the strategy argument.
Now is pretty clear that that version the BaseClass code can only ever return 1 as the hashcode. But you say that your code used to work, and you only changed the dependency. From that, we must conclude that the dependency has changed, and that the new version of the dependency is broken.
If anything is "bizarre" about this, it is that someone decided to implement the (new) BaseClass like that, and release it without testing it properly.
Actually, there is a possible way that you can get your CustomClass to work. The BaseClass::hashCode(ObjectLocator, HashCodeStrategy2) method is public and not final, so you could override it on your CustomClass as follows:.
#Override
public int hashCode(ObjectLocator locator, HashCodeStrategy2 strategy) {
return System.identityHashCode(this);
}
And indeed, it may be that the implementers of BaseClass intend you to do this. But I would still argue that BaseClass is broken:
Coding the class so that hashCode returns 1 as the default behavior is nasty.
There is no javadoc in BaseClass to explain the need to override the method.
Their (unannounced?) change to the behavior of BaseClass is an API breaking change. You shouldn't do stuff like that, without very good reason, and without warning.
The default behavior of the corresponding equals method is objectively wrong.
It's fine for two non-equal objects to have the same hash code. In fact, it's a mathematical requirement that this be allowed. Think about strings, for instance: there are infinitely many non-equal strings ("a", "aa", "aaa"...) yet only 2^32 possible int values. Clearly there must be different strings that share a hash code.
But HashSet knows this, so it uses the result from equals as well as the hash code. If only one of the objects is being added, then they don't just have there same hash code -- they are equal, as returned by the equals method. We can't determine why this is, let alone whether it's intentional, without the custom class's code.
The contract for Object says that equal objects must have the same hash code. But the converse is not true: objects with the same hash code do not have to be equal. The Javadocs say this explicitly:
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
Unless a class's docs explicitly tell you how it computes its hash code, you should probably not consider that an established contact, and you should expect that it could change between versions.
CustomObject class implementation (or one of its ancestors) is the problem here. Author of CustomObject (or one of its ancestors) has overridden toString, hashCode and equals methods in a wrong way without understanding the semantics of it and the implications of it. Here are your options (not necessarily in that order) to fix the problem:
You should notify the author of your dependency library about the problem in CustomObject class and get toString, hashCode and equals methods implemented or overridden in the right way. But remember - dependency code author can put you back in this place again in future.
Assuming CustomObject class is not final - extend CustomObject (please note - it is better named as CustomClass, not CustomObject) to have right implementation of toString, hashCode and equals methods. Use this extended class in your code instead of CustomObject class. This will give you better control because your dependency code cannot put you in this trouble again.
Use AOP to introduce overridden and right implementation of toString, hashCode and equals methods in CustomObject class. This approach is also future proof like the option 2 above.
I'm still pretty fresh to all this, but I'm working on attaining my OCAJP certification (Java). I remembered reading previously that the .equals method could be overridden when I came to this question:
Now these questions have been pretty evil as far as I'm concerned. Twisting every little thing you think you know to force you to learn all the minutiae. Now I had guessed E, but I didn't think D was correct. I mean 99.9% of the time, of course, but I thought it was a trick question based on the wording.
This got me thinking, is that true? I mean, if I get the question on the exam, I know how to answer it now, but in the deep dark abyss of overriding madness, is it possible to create a situation where a.equals(a) returns false? I feel like this would make Aristotle angry...
Note that a. b and c are instances of primitive wrapper classes (such as Integer, Double, etc...). These classes are final and cannot be extended, so you can't override their equals implementation.
Therefore a.equals(a) will always return true, since those classes implement equals properly.
Since equals(...) is not a final method of Object, yes, it is very well be possible in a different situation.
#Override
public boolean equals(Object obj) {
return false;
}
This question, however, specifically says that these are primitive wrappers (e.g. Integer, Boolean, etc.) and since these classes are final, you cannot extend them, thus a.equals(a) will always return true.
Integer a.equals( a ) can return false
But you have to be really evil and use reflections and Multithreading:
If you run this code, there is a chance that a racing condition can change the internal Value of myInt while the comparision takes place. If you want to simulate this condition, just set a breakpoint inside of Integer.intValue() run the code in debug and hit continue. This will create a delay which creates the race condition artificially and the console will return false.
class IntegerEqualsTest
{
public static void main( final String[] args )
{
final Integer myInt = new Integer( 420 );
new Thread() {
public void run() {
try {
final Field f = Integer.class.getDeclaredField( "value" );
f.setAccessible( true );
f.setInt( myInt, 100 );
} catch( final Exception e ) {}
}; }.start();
System.out.println( myInt.equals( myInt ) );
}
}
The other answers have already answered your question - no, this is not possible with the Java's primitive wrapper classes.
I'll try to address the "question behind the question": Is this possible with other classes?
[...] in the deep dark abyss of overriding madness, is it possible to
create a situation where a.equals(a) returns false? I feel like this
would make Aristotle angry...
This is actually a good question, and the answer is: Yes, it is possible to create such a situation, and yes, it would make Aristotle angry. Actually, I don't know if it would make Aristotle angry, not having known him, but it will certainly cause a lot of grief for whoever has to work with the code.
The thing is: There is a contract associated with Object.equals():
The equals method implements an equivalence relation on non-null
object references:
[...]
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
Javadocs for Object.equals
Yes, when creating your own class, you can violate this contract. There is (unfortunately) nothing in the compiler or runtime stopping you.
However, a lot of code relies on this contract, so if you violate it, any code that uses equals will probably fail in mysterious ways.
One example: Java's own Collection classes (java.util.Collection and friends) rely on equals. If an instance of a class that does not correctly implement equals is put into a collection, weird things happen, such as the collection sometimes containing the instance and sometimes not.
You can take a look at the implementations of all the primitive wrappers , i.e: Integer, Boolean, Character etc... you will see that the implementation is correct. The reason is that with equals, once of the checks being done is to check reference equality, and x.equals(x) as the both object and the argument are the same object.
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 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.
I'm using Eclipse to generate .equals() and .hashCode(), and there is an option labeled "Use 'instanceof' to compare types". The default is for this option to be unchecked and use .getClass() to compare types. Is there any reason I should prefer .getClass() over instanceof?
Without using instanceof:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Using instanceof:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
I usually check the instanceof option, and then go in and remove the "if (obj == null)" check. (It is redundant since null objects will always fail instanceof.) Is there any reason that's a bad idea?
Josh Bloch favors your approach:
The reason that I favor the instanceof approach is that when you use the getClass approach, you have the restriction that objects are only equal to other objects of the same class, the same run time type. If you extend a class and add a couple of innocuous methods to it, then check to see whether some object of the subclass is equal to an object of the super class, even if the objects are equal in all important aspects, you will get the surprising answer that they aren't equal. In fact, this violates a strict interpretation of the Liskov substitution principle, and can lead to very surprising behavior. In Java, it's particularly important because most of the collections (HashTable, etc.) are based on the equals method. If you put a member of the super class in a hash table as the key and then look it up using a subclass instance, you won't find it, because they are not equal.
See also this SO answer.
Effective Java chapter 3 also covers this.
If you use instanceof, making your equals implementation final will preserve the symmetry contract of the method: x.equals(y) == y.equals(x). If final seems restrictive, carefully examine your notion of object equivalence to make sure that your overriding implementations fully maintain the contract established by the Object class.
What I'm trying to get at here is that if you believe getClass() is the only reliable way to preserve symmetry, you are probably using equals() the wrong way.
Sure, it's easy to use getClass() to preserve the symmetry required of equals(), but only because x.equals(y) and y.equals(x) are always false. Liskov substitutability would encourage you to find a symmetry-preserving implementation that can yield true when it makes sense. If a subclass has a radically different notion of equality, is it really a subclass?
The reason to use getClass is to ensure the symmetric property of the equals contract. From equals' JavaDocs:
It is symmetric: for any non-null
reference values x and y, x.equals(y)
should return true if and only if
y.equals(x) returns true.
By using instanceof, it's possible to not be symmetric. Consider the example:
Dog extends Animal.
Animal's equals does an instanceof check of Animal.
Dog's equals does an instanceof check of Dog.
Give Animal a and Dog d (with other fields the same):
a.equals(d) --> true
d.equals(a) --> false
This violates the symmetric property.
To strictly follow equal's contract, symmetry must be ensured, and thus the class needs to be the same.
Angelika Langers Secrets of equals gets into that with a long and detailed discussion for a few common and well-known examples, including by Josh Bloch and Barbara Liskov, discovering a couple of problems in most of them. She also gets into the instanceof vs getClass. Some quote from it
Conclusions
Having dissected the four arbitrarily chosen examples of implementations of equals() , what do we conclude?
First of all: there are two substantially different ways of performing the check for type match in an implementation of equals() . A class can allow mixed-type comparison between super- and subclass objects by means of the instanceof operator, or a class can treat objects of different type as non-equal by means of the getClass() test. The examples above illustrated nicely that implementations of equals() using getClass() are generally more robust than those implementations using instanceof .
The instanceof test is correct only for final classes or if at least method equals() is final in a superclass. The latter essentially implies that no subclass must extend the superclass's state, but can only add functionality or fields that are irrelevant for the object's state and behavior, such as transient or static fields.
Implementations using the getClass() test on the other hand always comply to the equals() contract; they are correct and robust. They are, however, semantically very different from implementations that use the instanceof test. Implementations using getClass() do not allow comparison of sub- with superclass objects, not even when the subclass does not add any fields and would not even want to override equals() . Such a "trivial" class extension would for instance be the addition of a debug-print method in a subclass defined for exactly this "trivial" purpose. If the superclass prohibits mixed-type comparison via the getClass() check, then the trivial extension would not be comparable to its superclass. Whether or not this is a problem fully depends on the semantics of the class and the purpose of the extension.
This is something of a religious debate. Both approaches have their problems.
Use instanceof and you can never add significant members to subclasses.
Use getClass and you violate the Liskov substitution principle.
Bloch has another relevant piece of advice in Effective Java Second Edition:
Item 17: Design and document for inheritance or prohibit it
Correct me if I am wrong, but getClass() will be useful when you want to make sure your instance is NOT a subclass of the class you are comparing with. If you use instanceof in that situation you can NOT know that because:
class A { }
class B extends A { }
Object oA = new A();
Object oB = new B();
oA instanceof A => true
oA instanceof B => false
oB instanceof A => true // <================ HERE
oB instanceof B => true
oA.getClass().equals(A.class) => true
oA.getClass().equals(B.class) => false
oB.getClass().equals(A.class) => false // <===============HERE
oB.getClass().equals(B.class) => true
If you want to ensure only that class will match then use getClass() ==. If you want to match subclasses then instanceof is needed.
Also, instanceof will not match against a null but is safe to compare against a null. So you don't have to null check it.
if ( ! (obj instanceof MyClass) ) { return false; }
It depends if you consider if a subclass of a given class is equals to its parent.
class LastName
{
(...)
}
class FamilyName
extends LastName
{
(..)
}
here I would use 'instanceof', because I want a LastName to be compared to FamilyName
class Organism
{
}
class Gorilla extends Organism
{
}
here I would use 'getClass', because the class already says that the two instances are not equivalent.
instanceof works for instences of the same class or its subclasses
You can use it to test if an object is an instance of a class, an instance of a subclass, or an instance of a class that implements a particular interface.
ArryaList and RoleList are both instanceof List
While
getClass() == o.getClass() will be true only if both objects ( this and o ) belongs to exactly the same class.
So depending on what you need to compare you could use one or the other.
If your logic is: "One objects is equals to other only if they are both the same class" you should go for the "equals", which I think is most of the cases.
Both methods have their problems.
If the subclass changes the identity, then you need to compare their actual classes. Otherwise, you violate the symmetric property. For instance, different types of Persons should not be considered equivalent, even if they have the same name.
However, some subclasses don't change identity and these need to use instanceof. For instance, if we have a bunch of immutable Shape objects, then a Rectangle with length and width of 1 should be equal to the unit Square.
In practice, I think the former case is more likely to be true. Usually, subclassing is a fundamental part of your identity and being exactly like your parent except you can do one little thing does not make you equal.
Actually instanceof check where an object belongs to some hierarchy or not. ex: Car object belongs to Vehical class. So "new Car() instance of Vehical" returns true. And "new Car().getClass().equals(Vehical.class)" return false, though Car object belongs to Vehical class but it's categorized as a separate type.