Search code examples
javaarraysjvmruntimescjp

How are java arrays really working


Can someone explain me how arrays really work in Java.

I was surprised by the following code:

        Object test = new Object[2][2];
        Object test2 = new Object[] {
                new Object[2],new Object[2]
        };
        Object test3 = new Object[2][];
        ((Object[])test3)[0] = new Object[2];
        ((Object[])test3)[1] = new Object[2];
        System.out.println(test instanceof Object[]);
        System.out.println(test instanceof Object[][]);
        System.out.println(test2 instanceof Object[]);
        System.out.println(test2 instanceof Object[][]);
        System.out.println(test3 instanceof Object[]);
        System.out.println(test3 instanceof Object[][]);

only test2 is not an instance of Object[][]

What is the distinction at runtime?

Edit: i see some answers. Jon Skeet, please notice that i can do:

Object[] test4 = (Object [])test;
test4[0] = "blaaa";
test4[1] = "toto";
System.out.println(test4);

test instanceof Object[] returns true, and no exception is raised at runtime on the cast. According to the SCJP book of Sierra & Bates, test IS-A Object[][] but also a Object[]

But when trying to reassigning a new value with "test4[0] = "blaaa";", i get an exception: Exception in thread "main" java.lang.ArrayStoreException: java.lang.String at Main.main(Main.java:24)

So it seems at runtime, both test and test2 IS-A Object[], and both contains object arrays, but only one of them IS-A Object[][]


Solution

  • test2 refers to an array of two elements. Its type is just Object[] - so those elements can refer to any objects. In particular, you could write:

    // Valid
    Object[] foo = (Object[]) test2;
    foo[0] = "hello";
    

    whereas that wouldn't work for test:

    // Invalid - test isn't just an Object[], it's an Object[][]
    Object[] foo = (Object[]) test;
    test[0] = "hello";
    

    because the element type of the array that test refers to is Object[] rather than Object. The array "knows" that each element should be null or a reference to an Object[], so the VM will prevent it from storing a string.

    You can convert test to an Object[] in the same way that you can convert a String[] to an Object[] - that's called array covariance, and it was a mistake to allow it in my opinion. The VM has to check stores at execution time, as we've seen.