A simple post concerning the HashCode, Equals methods in Java world. These methods allow containers to ‘categorize’ the objects it contains and so find them more quickly.

This is particularly true of all containers whose name begins with ‘Hash’ (eg. HashSet, HashMap, …). These containers can contain objects on which an order is not necessarily defined (and easily defined) as opposed to containers whose name begins with ‘Tree’.

According to the Java API, the HashCode method must meet the following constraints:

  • The number generated (the hashCode) must remain the same from one call to another as it does not change one element (data member) used by the comparison method,
  • Two equal objects as defined in Method ‘equals’ should return the same hashCode,
  • Two unequal objects as defined in Method ‘equals’ can have the same hashCode (which is why the hashCode, which resembles an identifier, is not one).

It is important to define this method if you wish to place the objects of a class in containers efficiently and effectively. The fewer of ‘colisions’ in hashCodes operations will be faster on the containers.



Exemple n°1:

// 
// Example 1 
{
	System.out.println(" ---- Example1 ---- ");
	String obj1="123";
	System.out.println("obj1 hashCode: "+obj1.hashCode());
	String obj2="123";
	System.out.println("obj2 hashCode: "+obj2.hashCode());
			
	if(obj1==obj2){
		System.out.println("ok: ==");
	}else{
		System.out.println("nok: not ==");
	}

	if(obj1.equals(obj2)){
		System.out.println("ok: equals");
	}else{
		System.out.println("nok: not equals");
	}
}

.. the ouputs in console are:

 ---- Example1 ---- 
obj1 hashCode: 48690
obj2 hashCode: 48690
ok: ==
ok: equals



Exemple n°2:

// 
// Example 2 
{
	System.out.println(" ---- Example2 ---- ");
	String obj1="123";
	System.out.println("obj1 hashCode: "+obj1.hashCode());
	String obj2= new String("123");
	System.out.println("obj2 hashCode: "+obj2.hashCode());

	if(obj1==obj2){
		System.out.println("ok: ==");
	}else{
		System.out.println("nok: not ==");
	}

	if(obj1.equals(obj2)){
		System.out.println("ok: equals");
	}else{
		System.out.println("nok: not equals");
	}
}

.. the ouputs in console are:

 ---- Example2 ---- 
obj1 hashCode: 48690
obj2 hashCode: 48690
nok: not ==
ok: equals

Conclusion: HashCode, Equals methods
The obj1 and obj2 are getting references which are different. So the condition ‘(obj1==obj2)’ is false because both the obj1 and obj2 return the different reference.
So, to conclude with this post, you need to remember that:
– Objects in Java have hashcodes associated with them.
– Hash code is a signed number that identifies an object, but it is not unique for every object,
– Two or more objects can have the same hashcode and still be unequal,
– For two objects to be equal, they must have the same hashcode (necessary condition),
– But, if two objects have different hashcodes, they are definately unequal (sufficient condition),
– So, equal objects return equal hashcode, however, objects returning equal hashcode, may not be necessarily equal.

HashCode, Equals methods and ORM layer
A last comment concerning the ORM (Hibernate) layer, as explained in the below sites:
https://community.jboss.org/wiki/EqualsAndHashCode
and http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html, there are best strategies for implementation of equals() and hashcode() methods in the persistent classes.
Java’s Collections and Relational database relies heavily on being able to distinguish objects in a unified way. In Relational database’s this is done with primary keys, in Java we have equals() and hashCode() methods on the objects.

For example, below, a solution consisting to create an abstract class with the HashCode, Equals methods overridden. This class would be extended by the business class in ORM layer in order to compare correctly two objects.
Note: This class contains also a ‘version’ information for the ‘Hibernate versioning’.

public abstract class AbstractPersistentObject {
    private String id = IdGenerator.createId();

    private Integer version = null;


    public String getId() {
        return this.id;
    }

    public void setId(String value) {
        this.id = value;
    }

    public Integer getVersion() {
        return this.version;
    }

    public void setVersion(Integer value) {
        this.version = value;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null ||
                !(o instanceof AbstractPersistentObject )) {
            
            return false;
        }
            
        AbstractPersistentObject other  = (AbstractPersistentObject ) o;
            
        // if the id is missing, return false
        if (id == null) return false;
            
        // equivalence by id
        return id.equals(other.getId());
    }

    public int hashCode() {
        if (id != null) {
            return id.hashCode();
        } else {
            return super.hashCode();
        }
    }
...
}

The IdGenerator generates an unique Id:

public class IdGenerator {

    public static String createId() {
        UUID uuid = java.util.UUID.randomUUID();
        return uuid.toString();
    }
}

Example of business class ‘Book’ in ORM layer:

/**
 * Book persistence POJO
 * @author Huseyin Ozveren
 */
public class Book extends AbstractPersistentObject {
    
	// ------------------------- ATTRIBUTS
    private String title;
    private String category = null;
    private int year;
    private boolean previouslyPublished = false;
    private String isbn10;
    private String isbn13;
    private Set<Author> authors = new HashSet<Author>();
    private double price = 0;
	private Language language = null;
	private Set<Chapter> chapters = new HashSet<Chapter>();

	// ------------------------------------ GET/SET TERS
    public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

[...]
}

Best regards,