19

Why is the println printing "tom" and not showing any runtime exception after casting to List<Integer>, while it is not able to print the value 1 after casting to List<String>?

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String args[]) {

        List list = Arrays.asList(1, "tom");

        System.out.println(((List<Integer>) list).get(1));
        // "tom"

        System.out.println(((List<String>) list).get(0));
        // ClassCastException: Integer cannot be cast to String
    }
}
0x5C91
  • 3,360
  • 3
  • 31
  • 46
Aman
  • 213
  • 1
  • 7

4 Answers4

33

The first call of println is statically dispatched to PrintStream.println(Object) and the second call is dispatched to PrintStream.println(String). So for the second call the compiler puts an implicit cast to String which then fails with ClassCastException at runtime.

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
  • 2
    could you please elaborate on this, bcoz what i think in first case it shud go to PrintStream.println(Integer) if it goes PrintStream.println(String) for the second case or both shud have PrintStream.println(Object). – Aman Oct 08 '14 at 07:06
  • 7
    There is no `PrintStream.println(Integer)`. The compiler always dispatches to a method with the most specific signature. The most specific type for `Integer` is `Object`, and the most specific type for `String` is `String`. – ZhekaKozlov Oct 08 '14 at 07:10
3

The problem here is that the java compiler picks methods at compile time, not runtime. And at compile time it will pick the method PrintStream.print(String), not PrintStream.print(int) or PrintStream.print(Object), both of which would succeed.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
0
Integer i = new Integer(101);
String s = new String(i); // undefined and Invalid
StringBuffer sb = new StringBuffer(i); // defined and Valid

String s2 = "tom";
Integer i2 = new Integer(s2); //defined and valid

So when you assign a non generic list to a generic one it is assigned but when you are printing it it checks for type safety or define constructors for casting if there are valid and defined constructors then it is printed else shows class cast exception as the class can not be casted due to lack of undefined constructors for casting.

If I am wrong please help me out with the correct logic...

0

This type of problem can be avoided by using generics and is the primary motivation for using generics.

This is the actual flow of your code, from your second println() point of view:

  1. your code declares an ArrayList of type Object;

  2. It adds an Integer and a String to the ArrayList.

  3. It cast your list to a String list. Your list is marked as being restricted to String.

Java generics are a compile-time feature only so your list can accepts without any problem String and Integer elements. The object itself knows nothing about what types it's supossed to contain unlike to the compiler.

  1. It attemps to retreive the first element of your casted list which is supposed to be a String and cast it to String implicitly.

  2. Calls println(String x) from PrintStream class.

But this first element is actually not a String and is an Integer. You cannot cast an Integer to a String.

Read Generics in Java motivation section example.

Pier-Alexandre Bouchard
  • 5,135
  • 5
  • 37
  • 72