Friday, February 14, 2014

java.lang.ClassCastException: [I cannot be cast to java.util.List.

Caused by: java.lang.ClassCastException: [I cannot be cast to java.util.List.
Initially, I was confused by seeing the sentence "I cannot be cast to..."  However, it turns out that it should be read as:
"[I" cannot be cast to "java.util.List"
In this article, we will look at the class name (i.e., "[I") used in the class file.

What Is "[I"?


"[I" means array of "ints."  If you use jrcmd to generate a heap histogram,[1] you will see the following contents:

--------- Detailed Heap Statistics: ---------
30.0% 65027k   672176     -1k [C
10.2% 22119k   943754     -2k java/lang/String
10.0% 21592k   183036     -3k [Ljava/lang/Object;
 4.7% 10185k   434587     +0k java/util/HashMap$Entry
 4.7% 10114k    27029  -1254k [B
 4.5% 9783k   111539     +0k [Ljava/util/HashMap$Entry;
 1.9% 4075k    34777     +0k java/lang/Class
 1.9% 4058k    86590     +0k java/util/HashMap
 1.6% 3448k   147156     +0k javax/management/ObjectName$Property
 1.2% 2593k    82994     +0k java/util/LinkedHashMap$Entry
 1.1% 2398k    76765     +0k java/util/concurrent/ConcurrentHashMap$Segment
 1.0% 2215k     9311     +0k [I
 0.9% 1975k    18469     +0k [J

Besides "[I", we also find other array's class names:
  • [C
  • [B
  • [J

Array Representation[2]



In Java, arrays are full-fledged objects. Like objects, arrays are always stored on the heap. Also, multi-dimensional arrays are represented as arrays of arrays.

Arrays have a Class instance associated with their class, just like any other object. All arrays of the same dimension and type have the same class. The length of an array (or the lengths of each dimension of a multidimensional array) does not play any role in establishing the array's class. For example, an array of three ints has the same class as an array of three hundred ints. The length of an array is considered part of its instance data.

The name of an array's class has one open square bracket for each dimension plus a letter or string representing the array's type. For example, the class name for an array of ints is "[I". The class name for a three-dimensional array of bytes is "[[[B". The class name for a two-dimensional array of Objects is "[[Ljava.lang.Object".  Read [3] for more details of this naming convention for array classes.

Conclusions


This exception
java.lang.ClassCastException: [I cannot be cast to java.util.List
turned out to be a bug in the application code, which applies a type cast as shown below:

while (iter.hasNext()) 
{ 
  key = iter.next(); 
  val = (List) mEDefToVOAttrsMap.get(key);  <=== this line threw the Exception

The object returned from get() method was created in this way:

iArr = new int[val.size()]; 

This bug was exposed when we switched from JDK 6 to 7 in our tests.  Maybe due to security enforcements or other reasons, JDK 7 provides more runtime checking than JDK 6 does.  Therefore, this hidden bug has been revealed.

To conclude:
The compiler is not backwards compatible[4] because bytecode generated with JDK 7 won't run in Java 1.6 VM (unless compiled with the -target 1.6 flag[5]). But the JVM is backwards compatible, as it can run older bytecodes.

References

  1. Diagnosing OutOfMemoryError or Memory Leaks in JRockit (Xml and More)
  2. Array Representation (The Java Virtual Machine)
  3. The class File Format
  4. Is JDK “upward” or “backward” compatible?
  5. Cross-Compilation Options
  6. Java Products: All About Versions (Xml and More)







1 comment:

Unknown said...


begumzarakhan.blogspot.com

http://onlineproblemsolution.com/vashikaran-specialist-in-the-world/