The default behavior of Object.hashCode() is to return essentially the "address" of the object so that a.hashCode() == b.hashCode() if and only if a == b. How can I get this behavior in a user-defined class if a superclass already defines hashCode()? For instance:
class A {
public int hashCode() {
return 0;
}
}
class B extends A {
public int hashCode() {
// Now I want to return a unique hashcode for each object.
// In pythonic terms, it'd look something like:
return Object.hashCode(this);
}
}
Ideas?
System.identityHashCode(Object) provides this behaviour.
You would write this:
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
}
Please check the equals-method, that it only returns true, if the two objects are the same. Otherwise it would break behaviour described for equals and hashCode. (To be correct, the equals-method has to return false, if you get different hashcodes for two objects.) To provide an implementation of equals() that comply with the given hashCode()-method:
public boolean equals(Object other){
return this == other;
}
Use System.identityHashCode(). This is what IdentityHashMap uses.
You should be extremely wary of overriding an existing hashCode() with this though because you might break the hashCode contract, being that two objects that:
if a.equals(b) then a.hashCode() must equal b.hashCode()
You might break this by overriding the existing behaviour or you might need to override equals() too.
As Mnementh said it all, I'd just like to point out that hashCode() returning 0 (or any constant value) is valid (while lame). hashCode() can (and should) return different values for a and b only if !a.equals(b).
So for example you have
class A {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o instanceof A; // all objects are equal
}
}
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return this.hashCode().equals(o.hashCode());
}
}
Now you create two objects:
A a = new A();
A b = new B();
And suddenly a.equals(b), but !b.equals(a). Of course in more real life the equals() in A will be more sophisticated, but the problem still persist. To get rid of this problem you want to always call
if (super.equals(o)) return true;
at the beginning of new equals().
And since overriding hashCode() is strictly tied to overriding equals(), you want to make sure that everywhere super.equals() returned true for any two given objects, new hashCode() will return super.hashCode().
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.
I am trying to sync users between two different locations, therefore I keep existing users in a list, and hence do a comparison at a set time interval to see if the user should be added (new) or just updated.
I have a class User that is the subclass to Principal.
However my compare on the list does not work; I googled a bit and found that you have to override the equals method, and I do - but that code does not seem to be executed, it goes into ArrayList.class (primitive) and executes the contains method there.
Is this because my class already extends the superclass Principal?
What are my options if I want to execute the equals that I defined in User class?
public class User extends Principal
{
// some protected properties
...
#Override
public boolean equals(Object obj) {
return (this.getAlias().equals(((User) obj).getAlias())
&& this.getEmailAddress().equals(((User) obj).getEmailAddress()) && this.getCellNumber().equals(((User) obj).getCellNumber()));
}
}
The Principal class does not override the equals method, and more importantly, the properties I check for equality, is only contained in the subclass - User. Therefore it makes sense to check it here.
So in short, I have an ArrayList of Users, and I would like to check whether a certain User already exists or not. I call compare on the list, but it always fails, indicative that the method equals is not overrided properly in my code.
Any suggestions?
You should not implement equals() (and hashcode()) in a super class.
The reason is that when equals() returns true hashcode() must return same value
Imagine you have class Point2D and class Point3D extending the other.
Shall a point2D be equal to a point3D with same area coordinates?
If so then point3D must return the same hashcode as the "equal" point2D and that means that you cannot not store more that one poin3d with same area coordinates in a Hash bases collection (eg.: as keys in a HashMap).
Overriding equals is not as evident as it looks
equals with null must return false
equals with an object of a different class must return false because of symetry a.equals(b) <=> b.equals(a)
java
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass()!=getClass()) {
return false;
}
return Object.equals(this.getAlias(),((User) obj).getAlias())
&& Object.equals(this.getEmailAddress(),((User) obj).getEmailAddress())
&& Object.equals(this.getCellNumber(),((User) obj).getCellNumber()));
}
Also if object is used in hash collections it must override hashCode so that two objects that are equals must return the same hashCode, the contrary is not true.
The problem probably comes from you instantiating a List<Person>. The compiler can't know if every subclasses of Person override equals. To correct this, you should promise your compiler you'll override this method, which you can do by changing your Person class to an abstract class.
public abstract class Person {
#Override
public abstract boolean equals(Object o);
}
public class User extends Person {
// Some stuff...
#Override
public boolean equals(Object o) {
if (o == null || ! (o instanceof User))
return false;
// etc
}
}
According to the book Effective Java.If you have override the equals method,then you must override the hashcode method.
some advice when you override the equals method:
1. equals with null return false.
2. !(obj instanceof this) return false.
3. cast obj to this class and compare the parameters in the obj and this class.
return the result in the end
You should use the contains methode of the arrayList
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
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.
I'm writing some code to demonstrate equals and hashcode, for my implementation I used User example :
public class User {
private String name;
private String pass;
//...
#Override
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != this.getClass()) {
return false;
}
User rhs = (User) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.getName(), rhs.getName());
//eb.append(this.getPass(), rhs.getPass());
return eb.isEquals();
}
#Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder(17, 37);
hcb.append(this.getName());
hcb.append(this.getPass());
return hcb.toHashCode();
}
//...
public static void main(String[] args) {
User u1 = new User("foo","foo1");
User u2 = new User("bar","bar1");
System.out.println(u1.equals(u2));
System.out.println(u1.hashCode() + " ?= " + u2.hashCode());
User u3 = new User("foo","foo1");
User u4 = new User("foo","bar1");
System.out.println(u3.equals(u4));
System.out.println(u3.hashCode() + " ?= " + u4.hashCode());
}
}
Output:
false
2128613651 ?= 2129111967
true
2128615478 ?= 2214545177
I think I'm doing it wrong because my objects now can be equals but have a different hashcode (which is bad I know), but I want to make my Users equals only when their names are also equals.. And not when they have name AND pass equals.
How can I respect the conventions and have what I want to achieve?
Thanks for your help/clarification :)
Generally speaking, if a field is not present in your equals() method, you shouldn't reference it in your hashCode() method.
This ensures your hashcode() result will not change more often that your equals() result does. Consider changing your method to:
#Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder(17, 37);
hcb.append(this.getName());
return hcb.toHashCode();
}
That being said, it's rarely a good idea to create a non-intuitive equals() method. I would naturally assume your method would consider the password too, as might many of your future maintainers. Unit tests may be harder to write if true equality testing isn't conducted. Consider whether it would be better to create your own method, e.g.
public boolean usernameEquals(User other) {
...
}
All objects that are equals have the same hashcode. but not all object that have the same hashcode are equal.
All field you use in your hascode method should to be used in your equals method.
I wouldn't say that you are doing it wrong.
As far as the contract is concerned, If 2 objects are equal, then they should have the same hashCode. If 2 objects have the same hashCode, they need not be equal
If you define the equality of 2 User instances as - They are equal, if their names are equal, then you are good to go. As far as the hashCodes are concerned, you are right, because if the hashCodes of 2 objects are not equal, then the objects are not equal.
BTW Duncan is completely right in pointing out that it's rarely a good idea to create a non-intuitive equals() method
I’ve got a List<MyObject> list
And, I want to make use out of the list.contains() function.
It doesn’t seem to work at the moment, i.e. there are objects in the list that match, but is not being picked up by the comparator operator.
I’m guessing I need to write my own comparison operator in MyObject. What is the way to go about this?
You need to override public boolean equals(Object o) because contains uses it:
boolean contains(Object o)
Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).
See How to implement hashCode and equals method for a discussion of simple and correct ways to override equals.
You need to be especially careful to override equals(Object o) and not just implement equals(MyObject o).
You only have to implement your own version of equals and hashcode on MyObject class.
The default equals will not check the attribute you define in a class. That's why you get the wrong result.
Your class needs to implement equals(). It's also useful to implement the Comparable interface, if you ever want to sort your objects E.g.
class MyObject implements Comparable<MyObject> {
public int compareTo(MyObject o) {
// do the compare!
}
public boolean equals(Object o) {
// check equality
}
}
Notice the documentation for List's contains method:
List.contains()
It states that it used the equals method to determine equality and therefore determine if the element exists in the list.
Also, note that when you overload equals you must overload hashCode.
You have to override equals() in MyObject.
public class MyObject
{
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be MyObject at this point
MyObject test = (MyObject) obj;
// Compare 'this' MyObject to 'test'
}
public int hashCode()
{
// generate your hash
}
}