JDK-6421053 : Enum hashCode is order dependent
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-05-03
  • Updated: 2011-02-16
  • Resolved: 2006-05-03
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
$ java -version
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Suppose you have an Enum with two values.  The hashCode for those
values is dependent on the order in which hashCode is called on them.

The first value to have hashCode called on it always gets the same code, regardless of its ordinal or other associated with data.  This leads to a big problem when enums are handed from one JVM instance to another (say via a
socket or some other serialization.)   In that case, the two values' equals
method will still evaluate to true, but they have different values of hashCode,
breaking the contract (among other things).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the code below.  The code defines an Enum with two values (NUMERICAL and CATEGORICAL).  One instance of each gets put in a list, which we then shuffle.  The list is iterated over, and hashCode called on its elements,
so that about 1/2 of the time we're calling hashCode on NUMERICAL, and the
other half on CATEGORICAL.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
About 1/2 of the time I should see something like:
CATEGORICAL 20392474
NUMERICAL 11352996

The other half, I should see:
NUMERICAL 11352996
CATEGORICAL 20392474

The order of NUMERICAL / CATEGORICAL has swapped, but the same number stays associated with them.
ACTUAL -
About 1/2 of the time I get:
CATEGORICAL 20392474
NUMERICAL 11352996

But the other half are:
NUMERICAL 20392474
CATEGORICAL 11352996

The hashes for NUMERICAL and CATEGORICAL have been swapped.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.Collections;

public class EnumHash {

	public enum TDTDataType {
		NUMERICAL,
		CATEGORICAL;
	}
	
	public synchronized void doit()
	{
		ArrayList<TDTDataType> l = new ArrayList<TDTDataType>();
		l.add(TDTDataType.NUMERICAL);
		l.add(TDTDataType.CATEGORICAL);
		Collections.shuffle(l);
		for (TDTDataType type : l)
		{
			System.out.println(type + " " +type.hashCode());
		}
	}

	public static void main(String[] args) {
		EnumHash e = new EnumHash();
		e.doit();
	}

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Can't trust that hashCode will be the same on enum values that cross a JVM
boundary, so you have to wrap the values in some other class that computes a
hashCode on other attributes of the value.

Comments
EVALUATION Enums are handled specially by serialization and not actually copied over the wire.
03-05-2006