[英]Parametrized Method in Java: try-catch does not catch ClassCastException (on Android)
考慮創建一個新的Object並將其強制轉換為捕獲異常的try-catch塊中的String。 一切似乎都還好。 但是,如果我們在參數化函數的類似try-catch塊中將Object強制轉換為T,會發生什么情況呢? 未捕獲到異常,程序崩潰,引發ClassCastException。
更新:感謝您的回答和評論。 只是為了澄清一下:我理解為什么會引發異常(因為顯然將Object轉換為String)。
問題是 :為什么在運行時方法主體中沒有捕獲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:參數化方法不會失敗,只要我們簡單地調用它而不會得到如下結果:
test.<String>parametrizedCastTest();
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
由於類型擦除的實現方式,
final T ret = (T) obj;
實際上被翻譯成
final Object ret = (Object) obj;
並且parametrizedCastTest
的實際實現返回一個Object
,但是在任何被調用的地方,強制轉換都在此處完成:
final String test2 = Test.<String> parametrizedCastTest();
變成
final String test2 = (String) Test.parametrizedCastTest();
這就是為什么CCE發生在與您預期不同的地方。
通常,通用方法是通過用類型變量的上限(在本例中為Object)替換類型變量來實現的,然后它們的調用站點會秘密地將實際類型強制轉換為您應該退出的類型。
你應該在這里得到警告
final T ret = (T) obj;
關於不安全的演員表
在泛型方法中,您所知道的關於聲明的類型參數的全部是其界限。 您已將type參數聲明為
static <T> T parametrizedCastTest() {
沒有界限。 換句話說,它簡化為Object
。 演員在這里
final T ret = (T) obj;
這是不安全的,因為用作返回類型的T
實際上可以是其他任何值。 在您的示例中是。
final String test2 = Test.<String> parametrizedCastTest(); // fails here with ClassCastException without catching it
您正在嘗試將Object
類型的Object
分配給String
類型的變量。 這將永遠行不通。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.