Question

Reasonably enough, compiler would give you Raw type conversion warning for this:

//1
List<?> arrList = new ArrayList(); //raw type warning

However, compiler is ok (no warning) with this line:

//2
List<?>[] arr_of_arrList = new ArrayList[3];// no warning, why ?

So, without any complains from compiler I could further do:

 arr_of_arrList[0] = new ArrayList<String>();
 arr_of_arrList[1] = new ArrayList<Integer>();

Could you please explain why given array initialization (2) is considered type-safe as opposed to first list initialization (1) and what compiler is doing in case 2.

Was it helpful?

Solution

The compiler will also warn you when defining:

List<String>[] foo = new ArrayList[3];

This is because by its warning, the compiler trys to make you aware that lists stored in List<String>[] foo are possibly not of the generic type String. You could always end up with a List<Integer> in foo at run time:

 void main(){

    List<String>[] array = new List[1];
    fill(array);

    // The compiler could not check the array at compile time, so
    // the next line is permitted. But you just created yourself a time bomb.
    List<String> list = array[0];

    // The next line will finally cause a ClassCastException at runtime!
    // Good luck with debugging, especially if you have passed your list
    // arround for a while.
    // If you had defined List<?>[] foo, this assignment would have been
    // forbidden without explicit casting to String. But at least the "type"
    // of the array did not make you false promises about the generic type
    // of the list.
    String value = list.get(0);
 }

 // This method receives an array of lists. At runtime the generic type of
 // the array is gone. Therefore, a call to this method can be called with
 // anz List<SomeType>[] array as an argument. 
 void fill(List<?>[] array) {
   List<Integer> list = new ArrayList<Integer>();
   list.add(123)
   array[0] = list;
 }

In Java, arrays of generic types do not have a generic representation. Instead, all arrays of type List[] (in byte code the type is called [java.util.List) share one single representation, be it List<String> or List<Integer> or anyhing else. This is for reasons of backwards compatibility and for how arrays are represented in Java byte code. In other words, the compiler has no way to mark an array instance to only accept for example only List<String> objects. Instead, the compiler can only mark an array to accept subtypes of List as in before Java 5.

By stating

List<?>[] foo = new ArrayList[3];

you basically tell the compiler that you are aware of the compiler's inability to check for anything more than that all Lists in the array represented by foo are of some subtype of Object what is of course trivial. (With ? being equivalent to ? extends Object.) Or in other words, when using the wildcard ?, you ask the compiler to make sure that a List contained in foo is of any generic type. As stated before, because this demand is trivial, the compiler can actually discharge this demand and does not produce a warning.

Now here comes the catch:

class MyClass<T extends Number> { }

you could still not state:

MyClass<? extends Number>[] foo = new MyClass[3];

without a compiler warning. Why? I do not know. It should be the type-safest declaration. This makes even less sence when seeing that the synonymous declaration

MyClass<?>[] foo = new MyClass[3];

is accepted. For this reason, I asume that the compiler just skips type checking of generic type variables when arrays are involved entirely but makes sure that you recognized the impossibility of checking generic types of arrays by assuring that the user typed <?> compared to legacy code which completely lacks generic types.

OTHER TIPS

The ArrayStoreException has nothing to do with generics or wildcards at all. ArrayStoreException is a fact of life with arrays in Java, even in "type-safe" code:

Object[] foo = new Integer[3];
foo[0] = "bar";

This is exactly what is happening in your exception. The list returned by Arrays.asList is not a java.util.ArrayList, hence the ArrayStoreException.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top