Aman
Aman

Reputation: 213

Generics List<String> and List<Integer> not behaving as expected

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
    }
}

Upvotes: 19

Views: 1201

Answers (4)

Pier-Alexandre Bouchard
Pier-Alexandre Bouchard

Reputation: 5235

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.

Upvotes: 0

Raj Mansinka
Raj Mansinka

Reputation: 17

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...

Upvotes: 0

ZhekaKozlov
ZhekaKozlov

Reputation: 39536

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.

Upvotes: 33

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298898

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.

Upvotes: 3

Related Questions