Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it possible to get back an object of "incorrect-type" from the parametrized List in Java?

Here's a code snippet:

import java.util.*;
class Test
{
    public static void main(String[] args)
    {
        List<Integer> list = new ArrayList<>();
        addToList(list);
        Integer i = list.get(0); //#1 fails at run-time
        String s = list.get(0); //#2 fails at compile-time
        list.get(0); //#3 works fine
        System.out.println(list.get(0)); //#4 works fine, prints "string"
    }
    static void addToList(List list){
        list.add("string");
    }
}

I understand why is it possible to insert an object of String class in parametrized List.

It seems like I understand why code marked with #1 and #2 fails.

But why do #3 and #4 work? As far as I understand, the compiler adds appropriate casts after type-erasure, so when I call list.get(0), this method should return an Object previously casted to Integer. So why there is no ClassCastException occures at #3 and #4 at run-time?

like image 301
fromSPb Avatar asked Mar 04 '15 16:03

fromSPb


2 Answers

The #3 works because the object returned by get(int) is ignored. Whatever is stored at position 0 is returned, but since there is no cast, no error happens.

The #4 works fine for the same reason: the object produced by get(0) is treated like java.lang.Object subclass in println, because toString is called. Since toString() is available for all Java objects, the call completes without an error.

like image 128
Sergey Kalinichenko Avatar answered Oct 01 '22 14:10

Sergey Kalinichenko


First the reason why you can add a string to a List<Integer>. In the method

static void addToList(List list){

you use a raw type. Raw types exist purely for compatibility with older Java versions and should not be used in new code. Within the addToList method the Java compiler does not know that list should only contain integers, and therefore it doesn't complain when a String is added to it.

As for the different behavior of you two statements. Integer i = list.get(0) does not fail at compile time, because Java thinks that list only contains Integers. Only at runtime it turns out that the first element of list is not an Integer, and therefore you get a ClassCastException.

String s = list.get(0) fails at compile time because the Java compiler assumes that list only contains Integers, and so it assumes you try to assign an Integer to a String reference.

Just list.get(0) does not store the result of the method call. So neither at compile time nor at run time there is any reason for a failure.

Finally, System.out.println(list.get(0)) work because System.out is a PrintStream and has a println(Object) method, which can be called with an Integer argument.

like image 8
Hoopje Avatar answered Oct 01 '22 12:10

Hoopje