Java Reference
In-Depth Information
Set contains:[100, 200]
Set contains bk1: true
Set contains:[300, 200]
Set contains bk1: false
The program adds two BadKey objects called bk1 and bk2 to the Set . The first line in the output confirms that the
set contains the two objects. Then, the value for the id of bk1 object is changed from 100 to 300, which is confirmed
by the third line in the output. Since you have not removed the object bk1 from the set, the fourth line of the output is
unexpected. The fourth line of the output states that the object bk1 does not exist in the set, whereas the third line of
the output states that bk1 object is in the set.
What's wrong? Is the object bk1 in the set or not? The answer is that the object bk1 is in the set until you remove
it. If you use a for-each loop or an iterator to access all objects in the set, you will be able to get to it. However, the
collection (the set in this case) will not be able to find the object bk1 . The reason why the set is not able to find the
bk1 object is that the hash code value of the object bk1 changed after it was added to the set. Recall that HashSet is
a hash-based collection in Java. It uses the hash code of the object to locate the bucket in which the object will be
placed. When s.contains(bk1) is executed the second time, the hash code value of bk1 will be 300, which is the
returned value from its hashCode() method. When the object bk1 was placed in the set, its hash code was 200. Since
the hash code of the object bk1 has changed, the set will mistakenly identify a different bucket to locate it. Since the
set is looking for the object bk1 in a different bucket than the one in which it was placed, it does not find it. Where is
the problem? The problem lies in the hashCode() method of the BadKey class. The BadKey class is a mutable class and
the mutable state of this class (the id instance variable) has been used to compute its hash code, which is causing the
problem in locating the object in the set.
One way to fix this problem of apparently losing the BadKey objects in the set is to return a constant value from
its hashCode() method, say 99. The following is a valid implementation (not a good one, though) of the hashCode()
method of the BadKey class:
// BadKey.java
package com.jdojo.collections;
public class BadKey {
// Other code goes here...
public int hashCode() {
// Return the same value 99 all the time
return 99;
}
}
The above code will fix the problem of losing the object bk1 in the example shown in Listing 12-36 because hash
code value for an object of the BadKey class never changes. However, it introduces another issue that is related to the
performance of the hash-based collection. If you store objects of the BadKey class in a hash-based collection, say a
set, all objects will hash to the same bucket because all objects of the BadKey class will have the same hash code value,
which is 99. You fixed one problem and introduced another!
The main issue with the BadKey class is its mutability. It has only one instance variable id that is mutable. You
should consider the following guidelines when you work with mutable objects with hash-based collection:
You should avoid using objects of a mutable class as elements in a
Set and as keys in a Map ,
if possible. Consider using objects of immutable classes such String , Integer , or your own
immutable class as keys for a Map and elements for a Set .
Search WWH ::




Custom Search