简体   繁体   English

Java中的参数化方法:try-catch无法捕获ClassCastException(在Android上)

[英]Parametrized Method in Java: try-catch does not catch ClassCastException (on Android)

Consider creating a new Object and casting it to String within a try-catch block that catches an Exception. 考虑创建一个新的Object并将其强制转换为捕获异常的try-catch块中的String。 Everything seems to be ok. 一切似乎都还好。 But what does happen if we cast an Object to T within similar try-catch block in a parametrized function? 但是,如果我们在参数化函数的类似try-catch块中将Object强制转换为T,会发生什么情况呢? The exception is not catched and the program crashes raising a ClassCastException. 未捕获到异常,程序崩溃,引发ClassCastException。

Upd: thanks for answers and comments. 更新:感谢您的回答和评论。 But just to clarify: I understand why the exception is risen (because of casting Object to String obviously). 只是为了澄清一下:我理解为什么会引发异常(因为显然将Object转换为String)。

The question is : why does it NOT catch the ClassCastException during runtime in the method body? 问题是 :为什么在运行时方法主体中没有捕获ClassCastException?

class test
{
    public void doTests()
    {
        Log.i("", "====== CLASS CAST TEST ======");
        Log.i("", "====== REGULAR CAST TEST ");
        final String test1 = test.regularCastTest(); // the exception thrown is catched within the     method
        Log.i("", "====== PARAMETRIZED CAST TEST ");
        final String test2 = test.<String>parametrizedCastTest(); // fails here with     ClassCastException without catching it
        Log.i("", "------ CLASS CAST TEST END --");
    }   
    static <T> T parametrizedCastTest()
    {
        Object obj = new Object();
        try
        {
            final T ret = (T) obj;
            Log.d("", String.format("%s; %s",     obj.getClass().getSimpleName(), ret.getClass().getSimpleName())); // does not fail and prints 'Object; Object'
            return ret;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    static String regularCastTest()
    {
        Object obj = new Object();
        try
        {
            final String ret = (String) obj;
            return ret;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return "";
    }
}

PS: the parametrized method does not fail if we simply call it without getting the result like: PS:参数化方法不会失败,只要我们简单地调用它而不会得到如下结果:

test.<String>parametrizedCastTest();

LOGCAT LOGCAT

11-26 19:13:37.692: I/(13018): ====== CLASS CAST TEST ======
11-26 19:13:37.692: I/(13018): ====== REGULAR CAST TEST 
11-26 19:13:37.692: W/System.err(13018): java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
11-26 19:13:37.692: W/System.err(13018):    at com.kaypu.goods.test.regularCastTest(test.java:57)
11-26 19:13:37.692: W/System.err(13018):    at com.kaypu.goods.test.go1(test.java:30)
11-26 19:13:37.692: W/System.err(13018):    at com.kaypu.goods.AppGoods.doTests(AppGoods.java:285)
11-26 19:13:37.692: W/System.err(13018):    at com.kaypu.goods.AppGoods.onCreate(AppGoods.java:188)
11-26 19:13:37.692: W/System.err(13018):    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
11-26 19:13:37.692: W/System.err(13018):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4473)
11-26 19:13:37.692: W/System.err(13018):    at android.app.ActivityThread.access$1500(ActivityThread.java:144)
11-26 19:13:37.692: W/System.err(13018):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
11-26 19:13:37.692: W/System.err(13018):    at android.os.Handler.dispatchMessage(Handler.java:102)
11-26 19:13:37.692: W/System.err(13018):    at android.os.Looper.loop(Looper.java:136)
11-26 19:13:37.692: W/System.err(13018):    at android.app.ActivityThread.main(ActivityThread.java:5146)
11-26 19:13:37.692: W/System.err(13018):    at java.lang.reflect.Method.invokeNative(Native Method)
11-26 19:13:37.692: W/System.err(13018):    at java.lang.reflect.Method.invoke(Method.java:515)
11-26 19:13:37.692: W/System.err(13018):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)
11-26 19:13:37.692: W/System.err(13018):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566)
11-26 19:13:37.692: W/System.err(13018):    at dalvik.system.NativeStart.main(Native Method)
11-26 19:13:37.692: I/(13018): ====== PARAMETRIZED CAST TEST 
11-26 19:13:37.692: D/(13018): Object; Object
11-26 19:13:37.692: D/AndroidRuntime(13018): Shutting down VM
11-26 19:13:37.692: W/dalvikvm(13018): threadid=1: thread exiting with uncaught exception (group=0x415a2ce0)
11-26 19:13:37.692: E/AndroidRuntime(13018): FATAL EXCEPTION: main
11-26 19:13:37.692: E/AndroidRuntime(13018): Process: com.kaypu.goods, PID: 13018
11-26 19:13:37.692: E/AndroidRuntime(13018): java.lang.RuntimeException: Unable to create application com.kaypu.goods.AppGoods: java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4476)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.ActivityThread.access$1500(ActivityThread.java:144)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.os.Handler.dispatchMessage(Handler.java:102)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.os.Looper.loop(Looper.java:136)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.ActivityThread.main(ActivityThread.java:5146)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at java.lang.reflect.Method.invokeNative(Native Method)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at java.lang.reflect.Method.invoke(Method.java:515)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at dalvik.system.NativeStart.main(Native Method)
11-26 19:13:37.692: E/AndroidRuntime(13018): Caused by: java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
11-26 19:13:37.692: E/AndroidRuntime(13018):    at com.kaypu.goods.test.go1(test.java:32)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at com.kaypu.goods.AppGoods.doTests(AppGoods.java:285)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at com.kaypu.goods.AppGoods.onCreate(AppGoods.java:188)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
11-26 19:13:37.692: E/AndroidRuntime(13018):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4473)
11-26 19:13:37.692: E/AndroidRuntime(13018):    ... 10 more

Because of the way type erasure is implemented, 由于类型擦除的实现方式,

final T ret = (T) obj;

is actually translated to 实际上被翻译成

final Object ret = (Object) obj;

and the actual implementation of parametrizedCastTest returns an Object , but anywhere it's called , the cast is done there: 并且parametrizedCastTest的实际实现返回一个Object ,但是在任何被调用的地方,强制转换都在此处完成:

final String test2 = Test.<String> parametrizedCastTest();

becomes 变成

final String test2 = (String) Test.parametrizedCastTest();

which is why the CCE happens in a different place than you expected. 这就是为什么CCE发生在与您预期不同的地方。

As a general rule, generic methods are implemented by replacing type variables by their upper bound (Object, in this case), and then their call sites secretly do the actual casting to the type you're supposed to get out. 通常,通用方法是通过用类型变量的上限(在本例中为Object)替换类型变量来实现的,然后它们的调用站点会秘密地将实际类型强制转换为您应该退出的类型。

You should have gotten a warning here 你应该在这里得到警告

final T ret = (T) obj;

about an unsafe cast. 关于不安全的演员表

Within a generic method, all you know about a declared type parameter is its bound(s). 在泛型方法中,您所知道的关于声明的类型参数的全部是其界限。 You've declared the type parameter as 您已将type参数声明为

static <T> T parametrizedCastTest() {

with no bounds. 没有界限。 In other words, it reduces to Object . 换句话说,它简化为Object The cast here 演员在这里

final T ret = (T) obj;

is unsafe because T , which is used as a return type, can actually be anything else. 这是不安全的,因为用作返回类型的T实际上可以是其他任何值。 And in your example it is. 在您的示例中是。

final String test2 = Test.<String> parametrizedCastTest(); // fails here with ClassCastException without catching it

You're trying to assign an object of type Object to a variable of type String . 您正在尝试将Object类型的Object分配给String类型的变量。 This will never work. 这将永远行不通。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM