Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No ClassCastException is thrown inside Java generics

Below is the first Java generics I've ever written :

public class MyClass {

    public static <T> T castToAnotherType(Object param) {
        T ret = null;
        try {
            ret = (T) param;
        } catch (ClassCastException e) {
            System.out.print("Exception inside castToAnotherType()");
        }
        return ret;
    }

    public static void main(String[] args) {
        try {
            String obj = MyClass.castToAnotherType(new Object());
        } catch (ClassCastException e) {
            System.out.print("Exception outside castToAnotherType()");
        }
    }

}

The result is "Exception outside castToAnotherType()". Why did the exception not occur inside the generic method?

like image 335
Livy Avatar asked Nov 02 '14 13:11

Livy


2 Answers

T is effectively erased during compilation. See here:

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety. Generate bridge methods to preserve polymorphism in extended generic types.
  • Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

So your castToAnotherType gets T erased into ca. the following:

public static Object castToAnotherType(Object param) {
    Object ret = null;
    try {
        ret = (Object) param;
    } catch (ClassCastException e) {
        System.out.print("Exception inside castToAnotherType()");
    }
    return ret;
}

Which does obviously not produce any ClassCastException.

main(...) is a different story, it results into the following:

public static void main(String[] args) {
    try {
        String obj = (String) MyClass.castToAnotherType(new Object());
    } catch (ClassCastException e) {
        System.out.print("Exception outside castToAnotherType()");
    }
}

Which produces the ClassCastException when trying to cast Object to String.

Please see the Type Erasure part of the Generics tutorial.

like image 152
lexicore Avatar answered Oct 13 '22 04:10

lexicore


Well, since the compiler erases the generic type parameters, the casting inside the method is essentially equivalent to :

    Object ret = null;
    try {
        ret = (Object) param;
    } 
    ...

which is not a problem, regardless of what you pass to your method (since any Object can be cast to Object).

However, when you try to assign that Object to a String, in your main method, the ClassCastException occurs, since Object cannot be cast to a String.

like image 23
Eran Avatar answered Oct 13 '22 03:10

Eran