Reputation: 313
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?
Upvotes: 21
Views: 927
Reputation: 31744
If you look at ArrayList#get
method. It is this:
public E get(int index) {
//body
}
But at runtime it is actually:
public Object get(int index) {
//body
}
So when you do Integer i = list.get(0);
The compiler converts it to:
Integer i = (Integer)list.get(0);
Now at runtime, list.get(0)
returns an Object
type (which is actually String
). It now tries converting String => Integer
and it fails.
3
Because it is just:
list.get(0)
The compiler does add typecasting to anything. So it is just, list.get(0)
.
4
System.out.println(list.get(0));
list.get(0)
returns an Object
type. So public void println(Object x)
method of the PrintStream gets called.
Remember println(Object x) gets called and not println(String x).
Upvotes: 5
Reputation: 1109
4: The overload System.out.println(Object) is being called, since Integer <=_T Object (read: Integer is-a Object). Note that list.get(int) returns an Object in run-time since the type parameter gets erased. Now read
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
that tells you "Insert type casts if necessary to preserve type safety.", since a type cast is not necessary from Object to Object the ClassCastException cannot result.
For the same reason there is no type cast at 3, however side effects of the method call could happen of which List.get has none.
Upvotes: 2
Reputation: 12932
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 Integer
s. 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.
Upvotes: 8
Reputation: 726809
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.
Upvotes: 22
Reputation: 77206
The casts are applied to the return type of get
, not to the add
that's introducing the pollution. Otherwise, you'd be getting either a compile-time error or an exception at that point, since you can't cast a String
to an Integer
.
Upvotes: 1