No ClassCastException is thrown inside Java generics

社会主义新天地 提交于 2019-12-06 19:27:22

问题


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?


回答1:


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.




回答2:


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.




回答3:


All the generic types are erased in the compiled code. As far as the compiled code is concerned, castToAnotherType just returns an Object. However, your main method tries to assign it to a String, and it is not a String, so that produces a ClassCastException.

http://en.wikipedia.org/wiki/Type_erasure




回答4:


This is because of generic type erasure,

       T ret = null;
       try {
            ret = (T) param;
...

is translated by compiler into

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


来源:https://stackoverflow.com/questions/26699731/no-classcastexception-is-thrown-inside-java-generics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!