excalibur
excalibur

Reputation: 944

Java conversion Integer to String inconsistency

Why does conversion from collection of Integers to collection of String work but it fails when I actually has to convert the Integer to String? Why dosent it fail/catch it earlier? In my example below

static <T extends List<?> >
    void testConversion(T... args)
    {
        **// Didnt catch here?**
        List<String>[] slarray = (List<String>[])args;
        System.out.printf("Value is %s\n", slarray[0].get(0));
        **// Didnt catch here?**
        List<String> slist = (List<String>)args[0];
        // FAIL runtime exception
        String s2 = slist.get(0);
        // FAIL exception
        String s = slarray[0].get(0); 
    }

public static void main( String[] args )
    {
        testConversion(Arrays.asList(11,12), Arrays.asList(21,22));
    }

Upvotes: 0

Views: 71

Answers (2)

rgettman
rgettman

Reputation: 178243

When you provide a cast in your code, you are telling the compiler, "I know you have an instance of x, but I know it's really a y. Treat it as a y." If the cast is possible at all, then the compiler will allow it.

You are telling the compiler that args, which it knows is a T[], can be cast to a List<String>[]. You are also telling the compiler that args[0], which it accepts to be a T, is a List<String>.

It happens here that when calling testConversion, you are passing List<Integer>s. The type T is inferred to be Integer. However, because of type erasure, at runtime, they are really Lists. Also, the cast to List<String>[] and List<String> succeed, because at runtime, they are really casts to List[] and List, respectively.

When you compiled, you should have received an unchecked cast warning about casting to List<String>[] and to List<String>. It was warning you about type safety. It also inserted a cast to String on the call to get, because you told it that it was a List<String>. When you finally attempted to get a String out your List<String>, the JVM threw a runtime exception because the element really was an Integer.

When you casted args to a List<String>[], and when you casted args[0] to a List<String>, you lied to the compiler, but the JVM caught your lie.

Upvotes: 1

RealSkeptic
RealSkeptic

Reputation: 34618

This is because Java Generics are a compile time thing, and the actual type is erased when the program runs.

You defined your T as a "List of whatever". You then cast a reference to a "List of whatever" to a "List of String". It may be possible that this type cast will work (thus, it is not a compile-time error), and so the compiler doesn't complain, but leaves the issue to the run-time system.

In run time, it's just a reference to a List. So the run time environment doesn't complain either - you cast an array of List and assign it to an array of List, and the actual type is erased at this point.

But when it comes to getting the actual values, the run time environment can see that the value cannot actually be assigned to a String, and so it throws an exception.

Upvotes: 2

Related Questions