Why is the ArrayStoreException a RuntimeException?

Let's say we have the following program:

class Fruit {}

class Apple extends Fruit {} 

class Jonathan extends Apple {} 

class Orange extends Fruit {} 

public class Main { 
    public static void main(String[] args) { 
        Fruit[] fruit = new Apple[10];

        try { 
            fruit[0] = new Fruit(); // ArrayStoreException 
            fruit[0] = new Orange(); // ArrayStoreException 
        } catch(Exception e) { System.out.println(e); } 
    } 
}

Based on the Java documentation:

Thrown to indicate that an attempt has been made to store the wrong type of object into an array of objects.

I've read here that

When array is created it remembers what type of data it is meant to store.

If the array remembers what type of data it contains, it means that it KNEW the type of data it contains. But the snippet I posted is correctly compiled, so at compile time the array apparently doesn't know what type contains.

My questions are:

  1. Why is the ArrayStoreException thrown only at runtime?

  2. What information are missing to the compiler to realise that that assignment is not possible?

  3. Is there any cases in which such code is correct so no ArrayStoreException is thrown?
Jon Skeet
people
quotationmark

If the array remembers what type of data it contains, it means that it KNEW the type of data it contains.

At execution time, yes... just like at execution time, the type of an object is known:

Object x = "foo";
// The compiler won't let you call x.length() here, because the variable
// x is of type Object, not String.

The alternative would be to make very many array assignments implicitly throw a checked exception. That would be awful - similar to making NullPointerException checked.

What information are missing to the compiler to realise that that assignment is not possible?

Arrays are covariant, as you've seen. When the compiler sees an assignment into a Fruit[] of an Apple, it can't know what the actual type of that array is going to be. If it's Fruit[] or Apple[], that's fine. If it's Orange[] it's not. That information is only present at execution time - again, just like the compiler doesn't know whether an expression is definitely not null.

Is there any cases in which such code is correct so no ArrayStoreException is thrown?

Well if you have an array with a compile-time element of a final class, then you can't have any lower variance. So for example:

public void foo(String[] array) {
    array[0] = "x";
}

That can throw exceptions due to array being null or empty, but it will never throw an ArrayStoreException, because String is final. The implementation could never be a SubclassOfString[].

people

See more on this question at Stackoverflow