Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures


Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips


Submit News
Search the site here...
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Hash, hash, away it goes!

JavaFAQ Home » Story by Dr. Kabutz Go to all tips in Story by Dr. Kabutz

Bookmark and Share

The Java Specialists' Newsletter [Issue 031] - Hash, hash, away it goes!

Author: Dr. Heinz M. Kabutz

JDK version:

Category: Language

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile

Welcome to the 31st issue of "The Java(tm) Specialists' Newsletter", where we look at how Hash Sets can become really confused. I love hearing from my readers, so please send your comments, praises, criticisms, accolades. The best compliment to me is if you forward this newsletter to other Java fans, for example to your local Java User Group (JUG).

I remember hearing last year that Visual Basic (shudder) was the fastest growing computer language. A report this year found that Java is now growing faster then Visual Basic, which frankly shudders me even more. There are apparently about 2 million people on this globe hacking away at our poor, dear language. Rather discouraging is that my newsletter is only reaching a meager 0.065% of Java programmers. Then again, this is supposed to be The Java Specialists' Newsletter, so maybe there aren't that many of us out there who should be considered specialists Wink

How do you go from being an OO beginner to an OO guru? Simple answer: Experience! What if you can't wait 10 years to get that experience? Simple answer: Design Patterns! How can you learn Design Patterns? Simple answer: Ask me about my new course "Design Patterns - The Timeless Way of Coding".

Hash, hash, away it goes!

A few weeks ago, I received an email from Charles N. May who pointed out that it is quite easy to change an Integer using reflection in the same way that I showed in my article on Insane Strings. This is only possible because for some strange reason, or no reason at all, the data member value within the Integer class was not declared final.

Charles demonstrated the possible repercussions quite nicely by inserting the same Integer object several times into a java.util.HashSet, each time with different values. The contract of the java.util.Set says:

java.util.Set: A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.

It then goes on to say:

Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.

Interesting, but how do we define mutable, or immutable for that matter? I searched various Java texts but could not find a definition of what is meant by that. Let's try and define it for our use:

Immutable Class: A class where the state cannot be changed.

Simple enough, but what does state refer to? Is it a state descriptor of all the data members in the class? Or is it just the identity of the class? For example, let's consider the class Employee, which is part of the middle class ...

public class Employee {
  private final String name;
  private double salary;
  public Employee(String name, double salary) {
    this.name = name;
    this.salary = salary;
  public String getName() { return name; }
  public double getSalary() { return salary; }
  public void setSalary(double salary) { this.salary = salary; }

Is the Employee class mutable? If we say that the state consists of a conglomeration of all the data members then the answer is "Yes". If we say the state consists of the identity, the answer is "No", as we cannot change the state. However, it will get even more confusing as we also have to define identity. I would say that the identity is the part of the class that determines the value of e1.equals(e2) and e1.hashCode(). So, in Employee above, what is the identity? Is it name? Nope, it is actually the location of the object in memory. If we want the identity to be according to the name, we will have to write equals() and hashCode() methods, the details of which are below the scope of TJSN.

Since mutable is so hard to pin down, we should actually rewrite the javadocs for the java.util.Set interface:

Note: Great care must be exercised if objects with a mutable identity are used as set elements. The behaviour of a set is not specified if the value of an object is changed in a manner that affects equals comparisons or its hashcode while the object is an element in the set.

By the description above, we should be careful with objects like String, Integer, etc. where the identity can be changed at runtime using reflection. Alright, it is bad coding practice to change private data members using reflection, but Integer could easily have fitted the above description if the value had been final. Then again, as discussed in my "final" newsletter, it is also bad coding practice to not mark data members final when they should be. Incidentally, java.lang.String is a lost cause - we can never make that properly immutable since its identity is contained in an array and arrays are mutable. Once the 1'998'700 monkeys who don't read this newsletter discover you can change Strings, we are all lost!

So, what happens when you change the identity of an object while it is in the HashSet? Let's have a look:

import java.lang.reflect.Field; // I can't resist using that package
import java.util.*;

public class HashHashGone {
  // Did you know that you can make a final static data member
  // without a value (i.e. blank), as long as you set the value
  // in the static initializer?  I love making every possible
  // field final as it smokes out a lot of bugs.
  private static final Field intValue;
  static {
    try {
      intValue = Integer.class.getDeclaredField("value");
    } catch(NoSuchFieldException ex) {
      // we throw a RuntimeException from the static initializer
      // this will actually generate an Error and kill the thread
      // that first accessed GhostSet.
      throw new RuntimeException(
        "Serious error - no "value" field found in Integer");

  // This method changes the integer passed into the method to
  // the new value.
  private static void setInteger(Integer i, int newInt) {
    try {
      intValue.set(i, new Integer(newInt));
    } catch (IllegalAccessException ex) {
      throw new RuntimeException(
        "Serious error - field should have been accessible");

  // This method will be used later to print a detailed view of
  // the set, including the value, the class and the identity
  // hash code of the object.
  private static void printDetailed(Set set) {
    Iterator it = set.iterator();
    while(it.hasNext()) {
      Object val = it.next();
      System.out.print("	(toString()=" + val + ",class="
        + val.getClass().getName() + ",identityHashCode="
        + System.identityHashCode(val) + ")");
      if (it.hasNext()) System.out.print(", ");

  public static void main(String[] args) {
    if (args.length != 2) {
        "arguments:  ");
    int initialValue = Integer.parseInt(args[0]);
    int numberOfCopiesToInsert = Integer.parseInt(args[1]);

    Integer x = new Integer(initialValue);
    int currValue = initialValue;

    Set set = new HashSet();
    for (int i = 0; i < numberOfCopiesToInsert; i++) {
      setInteger(x, ++currValue);
    setInteger(x, initialValue);
    System.out.println("here's a set containing " +
      numberOfCopiesToInsert + " copies of Integer(" + x + "): ");
    System.out.println("detailed view of set:");
    System.out.println("and does it contain that Integer?: " +

    System.out.println("can the Integer be removed from the Set?");
    System.out.println("the Set contents after attempted remove:");

    setInteger(x, -initialValue);
      "altering the Integer to its opposite makes the Set contain:");

    setInteger(x, initialValue);
    currValue = initialValue;
    for (int i = 0; i < numberOfCopiesToInsert; i++) {
      setInteger(x, ++currValue);
    System.out.println("now all the elements have been removed "
      + "from the Set as it contains:");

When I run this with java HashHashGone 42 5, I get the following output:

here's a set containing 5 copies of Integer(42):
[42, 42, 42, 42, 42]
detailed view of set:
[       (toString()=42,class=java.lang.Integer,identityHashCode=6483656),
and does it contain that Integer?: false
can the Integer be removed from the Set?
the Set contents after attempted remove:
[42, 42, 42, 42, 42]
altering the Integer to its opposite makes the Set contain:
[-42, -42, -42, -42, -42]
now all the elements have been removed from the Set as it contains:

The HashSet actually contains a HashMap that keeps the entries as keys and values. The HashMap contains a rehash() method, which is called when the table grows past the threshold determined by the number of entries and fill factor. However, contrary to what I believed until I tried it out today, the rehash method does not consider the possibility that there may be two objects in different hash positions, but equal, in the table. Re-hashing will therefore not solve the problem described above.

Moral of the story, assuming there is still morality left in this world? (btw, have you ever considered how similar the words mortal, moral and mutable are?) OK, the moral is? Never create a class where the identity can be changed once the object has been created.

That's all for this week. Please take a moment to think of how I could improve this newsletter and pop me an email.



Copyright 2000-2004 Maximum Solutions, South Africa

Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

 Printer Friendly Page  Printer Friendly Page
 Send to a Friend  Send to a Friend

.. Bookmark and Share

Search here again if you need more info!
Custom Search

Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy