'Why doesn't this generic cast fail?

I'd expect this code to throw a ClassCastException:

public class Generics {
    public static void main(String[] args) {
        method(Integer.class);
    }

    public static <T> T method(Class<T> t) {
        return (T) new String();
    }
}

But it doesn't. Casting String to T doesn't fail, until I use the returned object somehow, like:

public class Generics {
    public static void main(String[] args) {
        method(Integer.class).intValue();
    }

    public static <T> T method(Class<T> t) {
        return (T) new String();
    }
}

Background: I created a Class which uses JAXB to unmarshal an XML file. It looks like this:

public static <T> T unmarshal(File file, Class<? extends T> clazz)

Depending on whether the root-Element is an anonymous type or not, either T or JAXBElement is being returned. JAXBElement of course, can't be casted to T. In my unit test, where I only called unmarshal() without doing something with the result, everything worked fine. In Code, it failed.

Why doesn't it fail directly? Is this a bug? If not, I'd like to understand why.



Solution 1:[1]

If T is not explicitly specified, the type erasure will treat it as Object. Therfore, your String object can be casted...

Solution 2:[2]

You don't explicitly specified, so the T is Object.

So the look up look like this

public class Generics {

    public static void main(String[] args) {
        Generics.method(Integer.class).intValue();
    }

    public static Object method(Class<Object> t) {
        return (Object) new String();
    }
}

If you specify the generic parameter:

public class Generics {

    public static void main(String[] args) {
        Generics.<Integer>method(Integer.class).intValue();
    }

    public static <T> T method(Class<T> t) {
        return (T) new String();
    }
}

You will get that exception .

Solution 3:[3]

I think that you can make stronger method definition like this:

public static <T extends Number> T method(Class<T> t) {
    return //// some code.
}

In this case line return new String() just cannot be compiled.

but line return new Integer(123); is compiled, works and does not require casting.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nicolas
Solution 2 Damian Leszczyński - Vash
Solution 3 AlexR