Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArrayList<Integer> automatically change its type to ArrayList <String>

public void run(){
    setFont("Courier-24");
    //Define list as ArrayList<Integer>
    ArrayList<Integer> list = new ArrayList<Integer>();
    readList(list);
}

private void readList(ArrayList list){
    list.add("Hello");
    list.add(2);
    println("list = "+list);
    println("Type of list = "+list.get(0).getClass());
    println("Type of list = "+list.get(1).getClass());
}

Result:

list = [Hello, 2]
Type of list = class java.lang.String
Type of list = class java.lang.Integer

Here is my code and result. My question is, how is it possible that ArrayList of type Integer can store String objects? What's the type of list now? And what mechanism is this?

like image 668
kahofanfan Avatar asked May 27 '15 21:05

kahofanfan


3 Answers

Java's generics don't actually change the underlying class or object, they just provide (mostly) compile-time semantics around them.

By passing an ArrayList<Integer> into a method expecting an ArrayList (which can hold anything), you're bypassing the compiler's ability to provide you with that type safety.

The Java Generics Tutorial explains this, and why Java implements generics this way. This page, in particular, focusses on it:

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

What that doesn't say is that this also allows code written with generics (like your run) to interact with code written without generics (like your readList), which is important when adding a feature to a very-well-established language with a huge library base (as they were when adding generics to Java).

like image 127
T.J. Crowder Avatar answered Oct 28 '22 19:10

T.J. Crowder


When you declare:

 private void readList(ArrayList list)

you are not specifying any type to this ArrayList so by default it is of type Object.

Both String and Integer (in fact all classes in java) are sub types of Object. Hence it is possible to add them to list.

For more information about generics without types please read here. In short generics types are for compile time checks only, so that you dont add wrong types (which can later cause exceptions. In this case your operations on String and Integer are compatible so luckily no errors).

like image 3
hitz Avatar answered Oct 28 '22 20:10

hitz


In your readList method's parameter you haven't constrained it to only Integer value types, thus list doesn't get the benefits of compile-time checking and must resort to runtime type checking.

like image 1
neuronaut Avatar answered Oct 28 '22 21:10

neuronaut