Related
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
What issues / pitfalls must be considered when overriding equals and hashCode?
The theory (for the language lawyers and the mathematically inclined):
equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and transitive). In addition, it must be consistent (if the objects are not modified, then it must keep returning the same value). Furthermore, o.equals(null) must always return false.
hashCode() (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).
The relation between the two methods is:
Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
In practice:
If you override one, then you should override the other.
Use the same set of fields that you use to compute equals() to compute hashCode().
Use the excellent helper classes EqualsBuilder and HashCodeBuilder from the Apache Commons Lang library. An example:
public class Person {
private String name;
private int age;
// ...
#Override
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
Also remember:
When using a hash-based Collection or Map such as HashSet, LinkedHashSet, HashMap, Hashtable, or WeakHashMap, make sure that the hashCode() of the key objects that you put into the collection never changes while the object is in the collection. The bulletproof way to ensure this is to make your keys immutable, which has also other benefits.
There are some issues worth noticing if you're dealing with classes that are persisted using an Object-Relationship Mapper (ORM) like Hibernate, if you didn't think this was unreasonably complicated already!
Lazy loaded objects are subclasses
If your objects are persisted using an ORM, in many cases you will be dealing with dynamic proxies to avoid loading object too early from the data store. These proxies are implemented as subclasses of your own class. This means thatthis.getClass() == o.getClass() will return false. For example:
Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy
If you're dealing with an ORM, using o instanceof Person is the only thing that will behave correctly.
Lazy loaded objects have null-fields
ORMs usually use the getters to force loading of lazy loaded objects. This means that person.name will be null if person is lazy loaded, even if person.getName() forces loading and returns "John Doe". In my experience, this crops up more often in hashCode() and equals().
If you're dealing with an ORM, make sure to always use getters, and never field references in hashCode() and equals().
Saving an object will change its state
Persistent objects often use a id field to hold the key of the object. This field will be automatically updated when an object is first saved. Don't use an id field in hashCode(). But you can use it in equals().
A pattern I often use is
if (this.getId() == null) {
return this == other;
}
else {
return this.getId().equals(other.getId());
}
But: you cannot include getId() in hashCode(). If you do, when an object is persisted, its hashCode changes. If the object is in a HashSet, you'll "never" find it again.
In my Person example, I probably would use getName() for hashCode and getId() plus getName() (just for paranoia) for equals(). It's okay if there are some risk of "collisions" for hashCode(), but never okay for equals().
hashCode() should use the non-changing subset of properties from equals()
A clarification about the obj.getClass() != getClass().
This statement is the result of equals() being inheritance unfriendly. The JLS (Java language specification) specifies that if A.equals(B) == true then B.equals(A) must also return true. If you omit that statement inheriting classes that override equals() (and change its behavior) will break this specification.
Consider the following example of what happens when the statement is omitted:
class A {
int field1;
A(int field1) {
this.field1 = field1;
}
public boolean equals(Object other) {
return (other != null && other instanceof A && ((A) other).field1 == field1);
}
}
class B extends A {
int field2;
B(int field1, int field2) {
super(field1);
this.field2 = field2;
}
public boolean equals(Object other) {
return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
}
}
Doing new A(1).equals(new A(1)) Also, new B(1,1).equals(new B(1,1)) result give out true, as it should.
This looks all very good, but look what happens if we try to use both classes:
A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;
Obviously, this is wrong.
If you want to ensure the symmetric condition. a=b if b=a and the Liskov substitution principle call super.equals(other) not only in the case of B instance, but check after for A instance:
if (other instanceof B )
return (other != null && ((B)other).field2 == field2 && super.equals(other));
if (other instanceof A) return super.equals(other);
else return false;
Which will output:
a.equals(b) == true;
b.equals(a) == true;
Where, if a is not a reference of B, then it might be a be a reference of class A (because you extend it), in this case you call super.equals() too.
For an inheritance-friendly implementation, check out Tal Cohen's solution, How Do I Correctly Implement the equals() Method?
Summary:
In his book Effective Java Programming Language Guide (Addison-Wesley, 2001), Joshua Bloch claims that "There is simply no way to extend an instantiable class and add an aspect while preserving the equals contract." Tal disagrees.
His solution is to implement equals() by calling another nonsymmetric blindlyEquals() both ways. blindlyEquals() is overridden by subclasses, equals() is inherited, and never overridden.
Example:
class Point {
private int x;
private int y;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return (p.x == this.x && p.y == this.y);
}
public boolean equals(Object o) {
return (this.blindlyEquals(o) && o.blindlyEquals(this));
}
}
class ColorPoint extends Point {
private Color c;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return (super.blindlyEquals(cp) &&
cp.color == this.color);
}
}
Note that equals() must work across inheritance hierarchies if the Liskov Substitution Principle is to be satisfied.
Still amazed that none recommended the guava library for this.
//Sample taken from a current working project of mine just to illustrate the idea
#Override
public int hashCode(){
return Objects.hashCode(this.getDate(), this.datePattern);
}
#Override
public boolean equals(Object obj){
if ( ! obj instanceof DateAndPattern ) {
return false;
}
return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
&& Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
}
There are two methods in super class as java.lang.Object. We need to override them to custom object.
public boolean equals(Object obj)
public int hashCode()
Equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.
public class Test
{
private int num;
private String data;
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
public int hashCode()
{
int hash = 7;
hash = 31 * hash + num;
hash = 31 * hash + (null == data ? 0 : data.hashCode());
return hash;
}
// other methods
}
If you want get more, please check this link as http://www.javaranch.com/journal/2002/10/equalhash.html
This is another example,
http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
Have Fun! #.#
There are a couple of ways to do your check for class equality before checking member equality, and I think both are useful in the right circumstances.
Use the instanceof operator.
Use this.getClass().equals(that.getClass()).
I use #1 in a final equals implementation, or when implementing an interface that prescribes an algorithm for equals (like the java.util collection interfaces—the right way to check with with (obj instanceof Set) or whatever interface you're implementing). It's generally a bad choice when equals can be overridden because that breaks the symmetry property.
Option #2 allows the class to be safely extended without overriding equals or breaking symmetry.
If your class is also Comparable, the equals and compareTo methods should be consistent too. Here's a template for the equals method in a Comparable class:
final class MyClass implements Comparable<MyClass>
{
…
#Override
public boolean equals(Object obj)
{
/* If compareTo and equals aren't final, we should check with getClass instead. */
if (!(obj instanceof MyClass))
return false;
return compareTo((MyClass) obj) == 0;
}
}
For equals, look into Secrets of Equals by Angelika Langer. I love it very much. She's also a great FAQ about Generics in Java. View her other articles here (scroll down to "Core Java"), where she also goes on with Part-2 and "mixed type comparison". Have fun reading them!
equals() method is used to determine the equality of two objects.
as int value of 10 is always equal to 10. But this equals() method is about equality of two objects. When we say object, it will have properties. To decide about equality those properties are considered. It is not necessary that all properties must be taken into account to determine the equality and with respect to the class definition and context it can be decided. Then the equals() method can be overridden.
we should always override hashCode() method whenever we override equals() method. If not, what will happen? If we use hashtables in our application, it will not behave as expected. As the hashCode is used in determining the equality of values stored, it will not return the right corresponding value for a key.
Default implementation given is hashCode() method in Object class uses the internal address of the object and converts it into integer and returns it.
public class Tiger {
private String color;
private String stripePattern;
private int height;
#Override
public boolean equals(Object object) {
boolean result = false;
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Tiger tiger = (Tiger) object;
if (this.color == tiger.getColor()
&& this.stripePattern == tiger.getStripePattern()) {
result = true;
}
}
return result;
}
// just omitted null checks
#Override
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.color.hashCode();
hash = 7 * hash + this.stripePattern.hashCode();
return hash;
}
public static void main(String args[]) {
Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
Tiger siberianTiger = new Tiger("White", "Sparse", 4);
System.out.println("bengalTiger1 and bengalTiger2: "
+ bengalTiger1.equals(bengalTiger2));
System.out.println("bengalTiger1 and siberianTiger: "
+ bengalTiger1.equals(siberianTiger));
System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
System.out.println("siberianTiger hashCode: "
+ siberianTiger.hashCode());
}
public String getColor() {
return color;
}
public String getStripePattern() {
return stripePattern;
}
public Tiger(String color, String stripePattern, int height) {
this.color = color;
this.stripePattern = stripePattern;
this.height = height;
}
}
Example Code Output:
bengalTiger1 and bengalTiger2: true
bengalTiger1 and siberianTiger: false
bengalTiger1 hashCode: 1398212510
bengalTiger2 hashCode: 1398212510
siberianTiger hashCode: –1227465966
Logically we have:
a.getClass().equals(b.getClass()) && a.equals(b) ⇒ a.hashCode() == b.hashCode()
But not vice-versa!
One gotcha I have found is where two objects contain references to each other (one example being a parent/child relationship with a convenience method on the parent to get all children).
These sorts of things are fairly common when doing Hibernate mappings for example.
If you include both ends of the relationship in your hashCode or equals tests it's possible to get into a recursive loop which ends in a StackOverflowException.
The simplest solution is to not include the getChildren collection in the methods.
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
What issues / pitfalls must be considered when overriding equals and hashCode?
The theory (for the language lawyers and the mathematically inclined):
equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and transitive). In addition, it must be consistent (if the objects are not modified, then it must keep returning the same value). Furthermore, o.equals(null) must always return false.
hashCode() (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).
The relation between the two methods is:
Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
In practice:
If you override one, then you should override the other.
Use the same set of fields that you use to compute equals() to compute hashCode().
Use the excellent helper classes EqualsBuilder and HashCodeBuilder from the Apache Commons Lang library. An example:
public class Person {
private String name;
private int age;
// ...
#Override
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
Also remember:
When using a hash-based Collection or Map such as HashSet, LinkedHashSet, HashMap, Hashtable, or WeakHashMap, make sure that the hashCode() of the key objects that you put into the collection never changes while the object is in the collection. The bulletproof way to ensure this is to make your keys immutable, which has also other benefits.
There are some issues worth noticing if you're dealing with classes that are persisted using an Object-Relationship Mapper (ORM) like Hibernate, if you didn't think this was unreasonably complicated already!
Lazy loaded objects are subclasses
If your objects are persisted using an ORM, in many cases you will be dealing with dynamic proxies to avoid loading object too early from the data store. These proxies are implemented as subclasses of your own class. This means thatthis.getClass() == o.getClass() will return false. For example:
Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy
If you're dealing with an ORM, using o instanceof Person is the only thing that will behave correctly.
Lazy loaded objects have null-fields
ORMs usually use the getters to force loading of lazy loaded objects. This means that person.name will be null if person is lazy loaded, even if person.getName() forces loading and returns "John Doe". In my experience, this crops up more often in hashCode() and equals().
If you're dealing with an ORM, make sure to always use getters, and never field references in hashCode() and equals().
Saving an object will change its state
Persistent objects often use a id field to hold the key of the object. This field will be automatically updated when an object is first saved. Don't use an id field in hashCode(). But you can use it in equals().
A pattern I often use is
if (this.getId() == null) {
return this == other;
}
else {
return this.getId().equals(other.getId());
}
But: you cannot include getId() in hashCode(). If you do, when an object is persisted, its hashCode changes. If the object is in a HashSet, you'll "never" find it again.
In my Person example, I probably would use getName() for hashCode and getId() plus getName() (just for paranoia) for equals(). It's okay if there are some risk of "collisions" for hashCode(), but never okay for equals().
hashCode() should use the non-changing subset of properties from equals()
A clarification about the obj.getClass() != getClass().
This statement is the result of equals() being inheritance unfriendly. The JLS (Java language specification) specifies that if A.equals(B) == true then B.equals(A) must also return true. If you omit that statement inheriting classes that override equals() (and change its behavior) will break this specification.
Consider the following example of what happens when the statement is omitted:
class A {
int field1;
A(int field1) {
this.field1 = field1;
}
public boolean equals(Object other) {
return (other != null && other instanceof A && ((A) other).field1 == field1);
}
}
class B extends A {
int field2;
B(int field1, int field2) {
super(field1);
this.field2 = field2;
}
public boolean equals(Object other) {
return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
}
}
Doing new A(1).equals(new A(1)) Also, new B(1,1).equals(new B(1,1)) result give out true, as it should.
This looks all very good, but look what happens if we try to use both classes:
A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;
Obviously, this is wrong.
If you want to ensure the symmetric condition. a=b if b=a and the Liskov substitution principle call super.equals(other) not only in the case of B instance, but check after for A instance:
if (other instanceof B )
return (other != null && ((B)other).field2 == field2 && super.equals(other));
if (other instanceof A) return super.equals(other);
else return false;
Which will output:
a.equals(b) == true;
b.equals(a) == true;
Where, if a is not a reference of B, then it might be a be a reference of class A (because you extend it), in this case you call super.equals() too.
For an inheritance-friendly implementation, check out Tal Cohen's solution, How Do I Correctly Implement the equals() Method?
Summary:
In his book Effective Java Programming Language Guide (Addison-Wesley, 2001), Joshua Bloch claims that "There is simply no way to extend an instantiable class and add an aspect while preserving the equals contract." Tal disagrees.
His solution is to implement equals() by calling another nonsymmetric blindlyEquals() both ways. blindlyEquals() is overridden by subclasses, equals() is inherited, and never overridden.
Example:
class Point {
private int x;
private int y;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return (p.x == this.x && p.y == this.y);
}
public boolean equals(Object o) {
return (this.blindlyEquals(o) && o.blindlyEquals(this));
}
}
class ColorPoint extends Point {
private Color c;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return (super.blindlyEquals(cp) &&
cp.color == this.color);
}
}
Note that equals() must work across inheritance hierarchies if the Liskov Substitution Principle is to be satisfied.
Still amazed that none recommended the guava library for this.
//Sample taken from a current working project of mine just to illustrate the idea
#Override
public int hashCode(){
return Objects.hashCode(this.getDate(), this.datePattern);
}
#Override
public boolean equals(Object obj){
if ( ! obj instanceof DateAndPattern ) {
return false;
}
return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
&& Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
}
There are two methods in super class as java.lang.Object. We need to override them to custom object.
public boolean equals(Object obj)
public int hashCode()
Equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.
public class Test
{
private int num;
private String data;
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
public int hashCode()
{
int hash = 7;
hash = 31 * hash + num;
hash = 31 * hash + (null == data ? 0 : data.hashCode());
return hash;
}
// other methods
}
If you want get more, please check this link as http://www.javaranch.com/journal/2002/10/equalhash.html
This is another example,
http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
Have Fun! #.#
There are a couple of ways to do your check for class equality before checking member equality, and I think both are useful in the right circumstances.
Use the instanceof operator.
Use this.getClass().equals(that.getClass()).
I use #1 in a final equals implementation, or when implementing an interface that prescribes an algorithm for equals (like the java.util collection interfaces—the right way to check with with (obj instanceof Set) or whatever interface you're implementing). It's generally a bad choice when equals can be overridden because that breaks the symmetry property.
Option #2 allows the class to be safely extended without overriding equals or breaking symmetry.
If your class is also Comparable, the equals and compareTo methods should be consistent too. Here's a template for the equals method in a Comparable class:
final class MyClass implements Comparable<MyClass>
{
…
#Override
public boolean equals(Object obj)
{
/* If compareTo and equals aren't final, we should check with getClass instead. */
if (!(obj instanceof MyClass))
return false;
return compareTo((MyClass) obj) == 0;
}
}
For equals, look into Secrets of Equals by Angelika Langer. I love it very much. She's also a great FAQ about Generics in Java. View her other articles here (scroll down to "Core Java"), where she also goes on with Part-2 and "mixed type comparison". Have fun reading them!
equals() method is used to determine the equality of two objects.
as int value of 10 is always equal to 10. But this equals() method is about equality of two objects. When we say object, it will have properties. To decide about equality those properties are considered. It is not necessary that all properties must be taken into account to determine the equality and with respect to the class definition and context it can be decided. Then the equals() method can be overridden.
we should always override hashCode() method whenever we override equals() method. If not, what will happen? If we use hashtables in our application, it will not behave as expected. As the hashCode is used in determining the equality of values stored, it will not return the right corresponding value for a key.
Default implementation given is hashCode() method in Object class uses the internal address of the object and converts it into integer and returns it.
public class Tiger {
private String color;
private String stripePattern;
private int height;
#Override
public boolean equals(Object object) {
boolean result = false;
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Tiger tiger = (Tiger) object;
if (this.color == tiger.getColor()
&& this.stripePattern == tiger.getStripePattern()) {
result = true;
}
}
return result;
}
// just omitted null checks
#Override
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.color.hashCode();
hash = 7 * hash + this.stripePattern.hashCode();
return hash;
}
public static void main(String args[]) {
Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
Tiger siberianTiger = new Tiger("White", "Sparse", 4);
System.out.println("bengalTiger1 and bengalTiger2: "
+ bengalTiger1.equals(bengalTiger2));
System.out.println("bengalTiger1 and siberianTiger: "
+ bengalTiger1.equals(siberianTiger));
System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
System.out.println("siberianTiger hashCode: "
+ siberianTiger.hashCode());
}
public String getColor() {
return color;
}
public String getStripePattern() {
return stripePattern;
}
public Tiger(String color, String stripePattern, int height) {
this.color = color;
this.stripePattern = stripePattern;
this.height = height;
}
}
Example Code Output:
bengalTiger1 and bengalTiger2: true
bengalTiger1 and siberianTiger: false
bengalTiger1 hashCode: 1398212510
bengalTiger2 hashCode: 1398212510
siberianTiger hashCode: –1227465966
Logically we have:
a.getClass().equals(b.getClass()) && a.equals(b) ⇒ a.hashCode() == b.hashCode()
But not vice-versa!
One gotcha I have found is where two objects contain references to each other (one example being a parent/child relationship with a convenience method on the parent to get all children).
These sorts of things are fairly common when doing Hibernate mappings for example.
If you include both ends of the relationship in your hashCode or equals tests it's possible to get into a recursive loop which ends in a StackOverflowException.
The simplest solution is to not include the getChildren collection in the methods.
In my most recent question, I was informed that I needed to override my equals and hashcode method (among other things). So I took a bit of time to read a few articles and attempted to come up with a proper implementation.
Here are some of the articles I read:
Hashcode on Wikipedia
StackOverflow Overriding equals and hashcode
StackOverflow Why does hashcode use multiplier 31
All the articles were pretty good. Since this is my first time attempting to do this, I just want to be sure I'm not making some simple (or dumb) mistake.
I will be using name to indicate whether my Person object is equivalent to another Person object. The reason for this, is that all the other variables can vary, but the name will always be unique.
Updated to reflect recommended changes
public class Person {
private String name;
private int p_number;
private String address;
//other variables
public Person(String a_name) {
name = a_name;
}
public String getName() {
return name;
}
//other getters and setters
#Override
public boolean equals(Object o) {
if(o == null)
return false;
if(o == this)
return true;
if(!(o instanceof Person))
return false;
Person p = (Person) o;
return name.equals(p.name));
}
#Override
public int hashCode() {
return name.hashCode();
}
}
My questions are as follows:
Did I implement these methods correctly?
Since name is the only variable that determines uniqueness, do I need to bother checking any of the other variables in hashcode?
I was reading on StackOverflow that 31 was chosen as a good prime number awhile ago, but choosing a larger prime is better now? Can someone confirm or deny this claim? (the claim was made in the third link above)
If I haven't implemented these methods properly, how can I change/improve them?
In equals():
if(name.equals(p.getName()))
return true;
Missing false, and you can just:
// Both are Person instances, no need to use the accessor here
return name.equals(p.name);
As to hashCode(), just return name.hashCode();
Also, can name be null? Your methods don't seem to account for that. (edit: answer: no)
As to your questions:
Since name is the only variable that determines uniqueness, do I need to bother checking any of the other variables in hashcode?
NO, certainly not! If your names are equal but ages different, this would lead to a different hash code for objects which are equal, and this violates the Object contract!
I was reading on StackOverflow that 31 was chosen as a good prime number awhile ago, but choosing a larger prime is better now? Can someone confirm or deny this claim? (the claim was made in the third link above)
This, no idea...
To be more complete about the .equals()/.hashCode() contract, I'll mention a utility class from Guava: Equivalence. An implementation of this abstract class for a given
class can allow you to create Sets, and therefore Maps, with these objects as members (keys) as if they had a different implementation of both of these functions:
Equivalence<MyClass> eq = ....;
Set<Equivalence.Wrapper<MyClass>> set = ...;
set.add(eq.wrap(myClassInstance));
This can be actually very useful in some scenarios...
Your equals needs to return a value in all cases, just change the end part to return the name.equals.
#Override
public boolean equals(Object o) {
...
return name.equals(o.getName());
}
Also your hashcode is actually detrimental, all it does is use the name.hashCode() but then multiply it by 31, better to use the default Java string hashcode from the name directly.
#Override
public int hashCode() {
return name.hashCode();
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why .equals method is failing on two same value objects?
This is really simple but I'm obviously missing something pretty big here.
Cat cat1 = new Cat("bob");
Cat cat2 = new Cat("bob");
System.out.println(cat1 == cat2);
//false since these references point to diferent objects
System.out.println(cat1.equals(cat2));
//returns false also??
Cat is just a simple class that only has a name.
What is going on here, how does equals() work? I was under the impression that it compared all the fields of the object. It seems that is not the case.
Do I need to overide it for all my classes?
Yes.
java.lang.Object provides very basic implementations of equals() and hashCode(). In particular, they don't go around reflecting on the type of the instance, which would (1) be dreadfully slow, and (2) carry a significant risk of comparing fields that you for various reasons don't want to compare in an equality comparison.
If you want equals() and hashCode() to actually be useful for comparing value equality (rather than reference equality which == does), you'll need to implement both within your own type.
Note that it's not enough to implement just equals(); while technically that will "work", it has the potential to lead to all kinds of weirdness. The simple rule of thumb is: neither or both, but never only one. And they must work on the same fields; if equals() says two instances are equal, then calling hashCode() on both must return the same value (also see the hashCode() contract).
It's also usually a good idea to override toString() with code to provide a meaningful description of the object in question. While not strictly needed, you only need to hit your head against this once in the debugger to realize the value. (Thanks #JonTaylor for mentioning this highly useful, related tidbit.)
And it's .NET that calls it GetHashCode(), while Java uses only hashCode() as the function name...
You need to override equals inside your Cat class. Default equals compares objects on references.
class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
#Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Cat))
return false;
Cat c = (Cat) obj;
return this.name == null ? false : this.name.equals(c.name);
}
#Override
public int hashCode() {
return this.name == null ? 31 : this.name.hashCode();
}
#Override
public String toString() {
return "Cat Name :" + name;
}
}
References
equals
hashCode
toString
The equals() provided by java.lang.object compares, simply speaking, a unique identifier for the object, though not entirely accurate you can think of it as a memory location, so it will only be true if you compare an object with itself (i.e. two references to the same object in memory)
You need to implement your own equals() method in your Cat class:
class Cat
{
String name;
#Override
public boolean equals(Cat other)
{
if (this.name.equals(other.name))
return true;
return false;
}
}
It would be wise to override hashCode() also, unless this is just a very basic application for homework or something. Also toString() can be useful to override as well.
http://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html
From [Java Doc]
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Without overriding the equals() method, the objects are different
Hence
System.out.println(cat1.equals(cat2)); // is false
That is because the == compare references and java.lang.Object.equals() translates to this==o thus return same as == in your case
In the case above you are using new operator to create two different objects hence both return false.
If you want .equals() to work as you are expecting, then override theequals() in your Cat class.
Ok, I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. But consider the following piece of code
package test;
public class MyCustomObject {
int intVal1;
int intVal2;
public MyCustomObject(int val1, int val2){
intVal1 = val1;
intVal2 = val2;
}
public boolean equals(Object obj){
return (((MyCustomObject)obj).intVal1 == this.intVal1) &&
(((MyCustomObject)obj).intVal2 == this.intVal2);
}
public static void main(String a[]){
MyCustomObject m1 = new MyCustomObject(3,5);
MyCustomObject m2 = new MyCustomObject(3,5);
MyCustomObject m3 = new MyCustomObject(4,5);
System.out.println(m1.equals(m2));
System.out.println(m1.equals(m3));
}
}
Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. This means that hashCode() overriding is an option rather being a mandatory one as everyone says.
I want a second confirmation.
It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode() API.
However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.
As per the documentation for Object class:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
Because HashMap/Hashtable will lookup object by hashCode() first.
If they are not the same, hashmap will assert object are not the same and return not exists in the map.
The reason why you need to #Override neither or both, is because of the way they interrelate with the rest of the API.
You'll find that if you put m1 into a HashSet<MyCustomObject>, then it doesn't contains(m2). This is inconsistent behavior and can cause a lot of bugs and chaos.
The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals and hashCode are consistent is one of the most important ones.
Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b) ==> a.hashCode() == b.hashCode() (NOTE that the inverse doesn't hold).
But as an additional information you can do this exercise:
class Box {
private String value;
/* some boring setters and getters for value */
public int hashCode() { return value.hashCode(); }
public boolean equals(Object obj) {
if (obj != null && getClass().equals(obj.getClass()) {
return ((Box) obj).value.equals(value);
} else { return false; }
}
}
The do this:
Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false
What you learn from this example is that implementing equals or hashCode with properties that can be changed (mutable) is a really bad idea.
It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.