You can't change the intrinsic type of a Java object by casting it. That includes arrays. The object's type is fixed when the object is allocated, and cannot be changed.
So casting an Object[]
to int[][]
will never work.
In this case, while int[][]
is a subtype of Object[]
, this is not sufficient for the typecast to be allowed at runtime. The actual rule in the JLS (5.5.3. Checked Casts at Run Time) is this:
"Here is the algorithm to check whether the run-time type R of an object is assignment compatible with the type T which is the erasure (§4.6) of the type named in the cast operator. If a run-time exception is thrown, it is a ClassCastException
." ...
"If R is a class representing an array type RC[], that is, an array of components of type RC:"
"If T is an array type TC[], that is, an array of components of type TC, then a run-time exception is thrown unless one of the following is true:"
In this case TC is int[]
and RC is Object
and Object
cannot be cast to int[]
. Hence you get an exception.
To illustrate why this must happen, consider this (hypothetical) example:
Object[] foo = new Object[3];
foo[0] = new Object();
int[][] bar = /* foo */
int[] mystery = bar[0];
Assuming that it is possible to "cast" the value of foo
, what should the mystery
variable point to? It can't be an int[]
because we didn't allocate one. It can't be an Object
instance because that would break static typing.
In fact, the "cast" has to be illegal, or else Java's static type system falls apart.
The difference between your example and mine is that foo is not actually an array of arrays of integers, whereas in my case it is. Why can the VM not see the "actual" type of the object?
The point is that static typing is (primarily) enforced by the compiler not by the JVM. While the JVM could (in theory) figure out that the types are OK at runtime (and throw exceptions if they are not), the compiler cannot do this because it cannot determine in general what the types are going to be.
Unfortunately I'm not actually creating the array myself. I'm getting it from another function and the Object[]
rather than int[][]
is, as far as I can tell, the side effect of some serialization that I have no control over.
Unfortunately you have to either copy the array ... or use it as an Object[]
and cast the elements to int[]
to use them; e.g.
Object[] foo = new Object[3];
foo[0] = new int[] { 1, 2, 3 };
foo[1] = new int[] { 4, 5, 6 };
foo[2] = new int[] { 7, 8, 9 };
...
int nine = ((int[]) (foo[2]))[2];
There is no "trust me it is really an int[][]
" option in Java.
If this a side-effect of serialization then the serialization is broken ... in some sense. Certainly, this won't happen with the standard Java Object Serialization protocol / implementation. That preserves the types of the objects ... unless you explicitly override them in the readObject
/ writeObject
methods, etcetera.