Previous
Index

Next


Objective 2, implementing hashCode

Distinguish between correct and incorrect implementations of hashcode methods.

Note on this Objective

This objective was new with the release of the JDK1.4 exam.The objectives as printed on the Sun website spell hashcode with a lower case letter c, the method inherited from Object has an upper case c as in hashCode. This is a strange topic to have been added to the objectives as it is possible to do vast amounts of very serious Java programming without ever having to trouble yourself with implementing hashcode. The real exam database is not plagued with questions on this topic, but as it is on the objectives you are advised to understand it.

It came from Object

The hashcode method is inherited from the great grandparent of all classes Object, thus an instance of any object can make a call to hashcode. The signature of hashcode is

public int hashCode()

Thus you might get an exam question that offers you some bogus signatures for hashcode that return types other than int or take some parameters instead of none. However I suspect the questions tend to be slightly more theoretical than this.

The int value that is returned is of particular use with the hash based Collection classes, ie

HashTable, HashSet, HashSet

The nature of hash based collections is to store keys and values. The key is what you use to look up a value. Thus you could for instance use a HashMap to store employee id in the key value and the employee name in the value part.

Generally a hashcode value will be the memory address of the object. You can demonstrate this to yourself quite easily with some trivial code such as.

public class ShowHash{
    public static void main(String argv[]){
        ShowHash sh = new ShowHash();
        System.out.println(sh.hashCode());
    }
}



When I compiled and ran this code I got an output of

7474923

Which is a representation of the memory address of that class on that run of the program. This illustrates one of the features of a hashcode is that it does not have to be the same value from one run of a program to another. If you think about the memory address of an object there is not guarantee at all what it will be from one run to another of a program.

Here is a quote from the JDK1.4 docs that covers this part of the requirements for a hashcode value.

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.”

Note how it says that the value returned from hashCode must be the same in the same program run provided no information used in the equals method comparisons on the object is modified. This brings us to the relationship between the equals and the hashCode method.

equals and hashCode

Every object has access to an equals method because it is inherited from the great grandparent class called Object. However this default object does not always do anything useful as by default it simply compares the memory address of the object. The downside of this can be seen dramatically when used with the String classes. If the String class did not implement its own version of the equals method comparing two Strings would compare the memory address rather than the character sequence. This is rarely what you would want, and for this reason the String class implements it's own version of the equals method that makes a character by character comparison.

Here is another of the points from the API documentation

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.

This principle is illustrated with the following code,

public class CompStrings{
    public static void main(String argv[]){
    String s1 = new String("Hello");
    String s2 = new String("Hello");
    System.out.println(s1.hashCode());
    System.out.println(s2.hashCode());
    Integer i1 = new Integer(10);
    Integer i2 = new Integer(10);
    System.out.println(i1.hashCode());
    System.out.println(i2.hashCode());
    }

}

This code will print out the same hashCode value for s1 and s2 and i1 and i2 on each run of the program. In theory it could print out different values under different circumstances.



Objects that are equal according to the equals method must return the same hashCode value

When two objects are not equal

It would be a plausible extrapolation from what I have covered so far to believe that two objects that are not equal according to the equals() method would have to return different hashCode values. This is not so, as stated in the API docs.

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



If two objects are not equal according to equals, they are not required to return different hashCode values.


It is worthwhile looking up the original API docs to understand the requirements of the hashCode method.

Questions

Question 1)

Which of the following statements are true?

1)The hashCode method of an object can return any primitive integral type


2) If two objects are equal according to the equals(Object) method, calling the hashCode method on each of the objects must produce the same result.

3) The hashcode method of an object must return the same value consistently from one execution of an application to another.

4) The signature of the hashcode method of the Object class is public int hashCode()

Question 2)

Given the following class definition

public class ValuePair implements Comparable{
    private int  iLookUp;
 
        
    public ValuePair(int iLookUp, String sValue){
        this.iLookUp=iLookUp;     
    }
    
  
    public void setLookUp(int iLookUp){
        this.iLookUp = iLookUp;
    }
    public int getLookUp(){
        return iLookUp;
    }
  
    public boolean equals(Object o){
      if( o instanceof ValuePair){
    ValuePair vp = (ValuePair) o;   
         if(iLookUp == vp.getLookup()){
        return true;
    }
    return false;
}

    
   
    public int compareTo(Object o) {
        ValuePair vp = (ValuePair) o;
        Integer iwLookUp= new Integer(vp.getLookUp());
        if(iwLookUp.intValue() < iLookUp){
            return -1;
        }
        
        if(iwLookUp.intValue() > iLookUp){
            return +1;
        }
        return 0;
    }
   
}

Which of the following would be valid hashCode methods?

1)

public int hashCode() { 
    return (int) System.currentTimeMillis(); 
}

2)

public char hashCode(){
    reutrn (char) iLookUp;
}

3)

public int hashCode(){
    return iLookUp;
}

4)

public int hashCode(){
    return iLookup * 100;
}

Question 3)

Given the following code

public class Boxes{
    String sValue;

    Boxes(String sValue){
    this.sValue=sValue;
    }
    
    public String getValue(){
    return sValue;
    }

    public boolean equals(Object o){
    String s = (String) o;
    if (sValue.equals(s) ){
        return true;
    }else{
        return false;
    }


    }

    public int hashCode(){
    return sValue.hashCode();

    }
}

Which of the following statements are true?

1) The hashCode method is correctly implemented
2) This class will not compile as String has no hashCode method
3) The hashCode method is not icorrectly implemented
4) This class will not compile because the compareTo method is not implemented

Question 4

Is the following statement true or false?

If it has been created correctly, calling the hashCode method of an object will always return the same value.

1) True
2) False

Answers

Answer to Question 1)

2) If two objects are equal according to the equals(Object) method, calling the hashCode method on each of the objects must produce the same result.

4) The signature of the hashcode method of the Object class is public int hashCode()

Answer to Question 2)

3)

public int hashCode(){
    return iLookUp;
}

4)

public int hashCode(){
    return iLookup * 100;
}

The value returned by the hashCode method must be an integer which rules out option 2 which returns a char value. Option 1 returns a version of the time in milliseconds which is certain to return a different value during a single run of the program, thus breaking one of the specific requirements of the contract for hashCode. The correct options, 3 and 4 may not be particularly good versions of the hashCode method but they are consistent with the equals value and return the correct data type.

Answer to Question 3)

1) The hashCode method is correctly implemented

The String class has its own implementation of the hashCode method. If it did not it would have inherited the hashCode method from Object which simply returns the memory address of the class instance.

Answer to Question 4

2) False

Be careful of any quesiton that uses the word always. The default inmplementation of hashCode for the Object class is to return the memory address of the object. A little knowledge of how Java works will tell you that there is no guarantee that an object will have the same memory address from one execution to another. A hashCode method must return the same value during the same run of a program but not necessarily from one program run to another. If you do a test on the hashCode of an instance of object you may find it seems to return the same memory address during multiple program runs, but there is no guarantee of this.

Other sources on this topic

The JDK1.4 API Docs
http://java.sun.com/j2se/1.4/docs/api/java/lang/Object.html#hashCode()

Manish Hatwalne
http://www.geocities.com/technofundo/tech/java/equalhash.html





Previous
Index

Next