2
private static void genericArrayTest() {
    ArrayList<? extends Exception>[] exceptionListArray = new ArrayList[10]; 
    Object[] exceptionObjectListArray  = exceptionListArray;

    ArrayList<String> wrongArrayList = new ArrayList<String>();
    wrongArrayList.add("String One");

    ArrayList<NullPointerException> exceptionList = new ArrayList<>();

    ArrayList rawList = new ArrayList();

    exceptionListArray[0] = exceptionList;
    //exceptionListArray[0] = wrongArrayList; // Compile error?
    //exceptionListArray[0] = rawList;

    exceptionObjectListArray[0] = wrongArrayList; 
// No compile time error, there is no ArrayStoreException why ?

    ArrayList<? extends Exception> list = exceptionListArray[0]; // No exception here as well ??
    Exception e = list.get(0); 
// Exception only when accessing data, why not ArrayStoreException when we stored wrong list ??
    System.out.println();
}

Can someone please explain what is going on ?

Google search says below array declaration is allowed
ArrayList<Exception>[] exceptionListArray = new ArrayList[10];
but not this
ArrayList<Exception>[] exceptionListArray = new ArrayList<Exception>[10];
What is the difference between these two declaration & why one is allowed not other one?

Creating an array to store generic types in Java is talks about how to create generic array. But this question is not about how to create generic array, its about why ArrayStoreException is not thrown at runtime & difference in generic array creation syntax in java

Community
  • 1
  • 1
Dhanaraj Durairaj
  • 644
  • 1
  • 6
  • 17
  • Check here for your last question: http://stackoverflow.com/a/16415586/986169. Regarding exceptionObjectListArray, it is declared as an array of Object types. So any array of a type that extends Object can be assigned to it. – giorashc May 03 '15 at 13:32
  • @giorashc From above link, I got into - http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createArrays. It says "If arrays of parameterized lists were allowed, code would fail to throw the desired ArrayStoreException". But, it is happening now as well with above code block correct ? So the question is what does java achieved by allowing 'ArrayList[] exceptionListArray = new ArrayList[10]; ' ? – Dhanaraj Durairaj May 03 '15 at 13:37
  • possible duplicate of [Creating an array to store generic types in Java](http://stackoverflow.com/questions/16415255/creating-an-array-to-store-generic-types-in-java) – Joe May 03 '15 at 13:58
  • I don't think that's a complete duplicate because this question asks about ArrayStoreException. – Radiodef May 03 '15 at 14:40

1 Answers1

3

In Java, generic parameterizations do not have a class which distinguishes them from each other:

ArrayList<Exception> : class is ArrayList
ArrayList<String>    : class is ArrayList

This is because generics are implemented with type erasure, which means that during compilation, they are replaced with casting:

ArrayList<Exception> list = new ArrayList<Exception>();
list.add(new Exception());
Exception e = list.get(0);

becomes:

ArrayList list = new ArrayList();
list.add(new Exception());
Exception e = (Exception) list.get(0);

No ArrayStoreException is thrown because ArrayList<Exception> and ArrayList<String> have the same type during program execution.

A generic array is disallowed because there is no way to perform these checks on the type parameters during execution. (Because the type parameters don't exist anymore.)

When we have this:

ArrayList<Exception>[] a =
    new ArrayList[10];

It's called an unchecked conversion. a is actually an ArrayList[], an array which stores any ArrayList but we've basically said "pretend it's an ArrayList<Exception>[] for the time being". The array object a points to is still an ArrayList[].


See the following program to illustrate:

import java.util.*;

class Example {
    public static void main(String[] args) {
        ArrayList<Exception> a = new ArrayList<Exception>();
        ArrayList<String>    b = new ArrayList<String>();

        System.out.println("ArrayList<Exception> class is:");
        System.out.println("\t" + a.getClass());
        System.out.println("ArrayList<String> class is:");
        System.out.println("\t" + b.getClass());
        System.out.println(
            "ArrayList<Exception> class == ArrayList<String> class:");
        System.out.println("\t" + ( a.getClass() == b.getClass() ));

        ArrayList<Exception>[] c = new ArrayList[0];
        ArrayList<String>[]    d = new ArrayList[0];

        System.out.println("ArrayList<Exception>[] class is:");
        System.out.println("\t" + c.getClass());
        System.out.println("ArrayList<String>[] class is:");
        System.out.println("\t" + d.getClass());
        System.out.println(
            "ArrayList<Exception>[] class == ArrayList<String>[] class:");
        System.out.println("\t" + ( c.getClass() == d.getClass() ));
    }
}

http://ideone.com/dfCZjy

Output:

ArrayList<Exception> class is:
    class java.util.ArrayList
ArrayList<String> class is:
    class java.util.ArrayList
ArrayList<Exception> class == ArrayList<String> class:
    true
ArrayList<Exception>[] class is:
    class [Ljava.util.ArrayList;
ArrayList<String>[] class is:
    class [Ljava.util.ArrayList;
ArrayList<Exception>[] class == ArrayList<String>[] class:
    true
Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • Type erasure or not, every class in Java extends from `Object`. I guess that should be sufficient to explain why an `ArrayStoreException` is not thrown. – Chetan Kinger May 03 '15 at 13:40
  • 1
    @ChetanKinger I don't really see how that's relevant. – Radiodef May 03 '15 at 13:41
  • @ChetanKinger That's not relevant because the class of `exceptionObjectListArray` is `ArrayList[]`, not `Object[]`. It is possible to get an `ArrayStoreException` for an array with compile-time type `Object[]`. – Paul Boddington May 03 '15 at 13:45
  • @pbabcdefp Can you elaborate on what you mean by `the class of exceptionObjectListArray is ArrayList[]`? Do you mean at runtime because at compile time, it is an `Object[]` array right? – Chetan Kinger May 03 '15 at 13:49
  • @ChetanKinger Try [`exceptionObjectListArray.getClass()`](http://ideone.com/ThCL25) – Radiodef May 03 '15 at 13:52
  • @ChetanKinger Yes, at runtime. If you use `a = new ArrayList[]`, `a.getClass()` will show you it's an `ArrayList[]`. You get the same result if you write `Object[] b = a` and then do `b.getClass()`. Even though the compile-time type of `b` is `Object[]` it will still throw an `ArrayStoreException` at runtime if you put something in it that is not an `ArrayList`. – Paul Boddington May 03 '15 at 13:53
  • @pbabcdefp Understood. @Radiodef, `exceptionObjectListArray.getClass()` is the runtime type. Thus the quesiton. – Chetan Kinger May 03 '15 at 13:54
  • @Radiodef Thanks for the explanation. I have one small clarification. Though `a` is `ArrayList[]`, compiler complains if we do `a[0] = new ArrayList()`. Why compiler is designed such a way, when it's not going to matter anyway during runtime ? Compiler can accept that statement right as runtime is not going to have any issues with that statement ? – Dhanaraj Durairaj May 03 '15 at 16:08
  • @Radiodef In your terms why compiler is pretending to be `ArrayList[]` when it does not matter at all during runtime ? Both compiler & runtime should think in same way isn't it ? – Dhanaraj Durairaj May 03 '15 at 16:15
  • @Radiodef It's not `a` it's `c` & `c[0] = new ArrayList()` Sorry for the inconvenience – Dhanaraj Durairaj May 03 '15 at 16:24
  • Generics are preventing us from making a certain kind of error which arrays allow us to do. The generic type system altogether disallows the situation which causes an `ArrayStoreException`. What you have here is a strange collision between different systems which were [designed with different motivations](http://stackoverflow.com/q/18666710/2891664). The sound advice is to not try to use both. Instead pick one or the other, either `Exception[][]` or `List>`. There isn't a good reason they behave this way when they are combined. – Radiodef May 03 '15 at 16:44