I'm encountering a bizarre issue on a JBoss server where two classes are producing the same hashCode()
.
Class<?> cl1 = Class.forName("fqn.Class1");
Class<?> cl2 = Class.forName("fqn.Class2");
out.println(cl1.getCanonicalName());
out.println(cl2.getCanonicalName());
out.println(cl1.hashCode());
out.println(cl2.hashCode());
out.println(System.identityHashCode(cl1));
out.println(System.identityHashCode(cl2));
out.println(cl1 == cl2);
out.println(cl1.equals(cl2));
out.println(cl1.getClassLoader().equals(cl2.getClassLoader()));
Produces:
fnq.Class1
fnq.Class2
494722
494722
494722
494722
false
false
true
I normally wouldn't care, but we're using a framework that caches setters using a key that is comprised of hashcodes from the class and a property name. It's a bad design for caching, but it's beyond my control at the moment (OGNL 3.0.6 in the latest Struts 2.3.24, see source. A newer OGNL fixes the issue, but it won't be in Struts until 2.5, currently in beta.)
What makes the issue somewhat bizarre to me is
I read that the RNG hashcode generator in Hotspot (the "0" strategy) can produce duplicates if there's racing threads, but I can't imagine classloading triggering that behavior.
Does Hotspot use special hashcode handling when creating a Class
instance?
HashCode collisions Whenever two different objects have the same hash code, we call this a collision. A collision is nothing critical, it just means that there is more than one object in a single bucket, so a HashMap lookup has to look again to find the right object.
If two objects have the same hashcode then they are NOT necessarily equal. Otherwise you will have discovered the perfect hash function. But the opposite is true: if the objects are equal, then they must have the same hashcode .
When two unequal objects have the same hash value, this causes a collision in the hash table, because both objects want to be in the same slot (sometimes called a bucket).
Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the null reference is zero. So even if the hashcode() is overridden, it should not effect it.
java.lang.Class
does not override hashCode
, nor JVM handles it somehow specially. This is just the regular identity hashCode inherited from java.lang.Object
.-XX:hashCode=0
(default in JDK 6 and JDK 7) the identity hashCode is calculated using global Park-Miller random number generator. This algorithm produces unique integers with the period of 2^31-2
, so there is almost no chance that two objects have the same hashCode except for the reason below.hashCode
method. So it does not matter when and how the classes are loaded. The problem can happen with any two objects if hashCode
is called concurrently.-XX:hashCode=5
(default in JDK 8). This option uses thread-local Xorshift RNG. It is not subject to race conditions and is also faster than Park-Miller algorithm.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With