hlucasfranca hlucasfranca - 7 months ago 17
Java Question

Why Java allows a non-generics List be passed to a generics List constructor?

I'm studying for OCA certification and in the ArrayList topic, after making some tests, I came with the following issue:

import java.util.ArrayList;

public class ArrayLists{

public static void main(String[] args) {

ArrayList list = new ArrayList();

list.add(1);
list.add("hi");

// Passing a non-Generics list to a Generics list
ArrayList<String> list2 = new ArrayList<>(list);

for(int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}

// error, cannot cast Integer to string
for(String s : list2) {
System.out.println(s);
}

}
}


Why Java allows this behavior, since I'll get a runtime error running the program?

Answer

It the same as if you have typed:

    ArrayList<Object> list = new ArrayList<Object>(); 

    list.add(1);
    list.add("hi");

    // Passing a non-Generics list to a Generics list
    ArrayList<String> list2 = new ArrayList<>(list); 

According to Type Erasure, when you don't specify type parameters Object is used. That is why it is possible to add Integer and String. In your example the compiler does not know what types will go into Array. In order to be backward compatible with code written before Generics where introduced (Java 5), this is allowed. However implicit casting of Integer to String is not possible, but is need in the second constructor - a runtime exception occurs. In my example compilation fails, because the compiler refuses to create ArrayList with Strings from ArrayList with Objects.