为什么@SneakyThrows不抛出ClassCastException?

问题描述 投票:0回答:1

在开始之前,让我先说一下:我对此处描述的类型推断不感兴趣

Java 8 中异常类型推断的一个独特功能

这只是为了避免混淆。

我感兴趣的是为什么下面的代码可以工作而不会抛出一个

ClassCastException

import java.sql.SQLException;

public class GenericThrows {
    static <T extends Exception> void test(Exception d) throws T {
        throw (T) d;
    }

    public static void main(String[] args) {
        GenericTest.<RuntimeException>test(new SQLException());
    }
}

使用以下命令编译代码:

javac -source 1.7 -target 1.7 GenericThrows.java

它产生:

Exception in thread "main" java.sql.SQLException
        at GenericTest.main(GenericTest.java:9)

我对 Java 泛型和类型擦除的心理模型(以及为什么我认为这没有意义):

静态方法编译时:

static <T extends Exception> void test(Exception d) throws T {
        throw (T) d;
    }

类型擦除擦除所有泛型类型并将它们替换为给定类型的上限,因此该方法实际上变为:

static void test(Exception d) throws Exception {
        throw (Exception) d;
    } 

我希望我是对的。

main方法编译时:

static <T extends Exception> void test(Exception d) throws T {
        throw (T) d;
    }

    public static void main(String[] args) {
        GenericTest.<RuntimeException>test(new SQLException());
    }

类型参数被具体类型替换:

java.lang.RuntimeException

因此该方法实际上变为:

static void test(Exception d) throws RuntimeException {
        throw (RuntimeException) d;
    }

我希望我是对的。

所以,当我尝试将

SQLException
转换为
RuntimeException
时,我应该得到一个
ClassCastException
,这正是如果我编写没有泛型的代码时会发生的情况:

import java.sql.SQLException;

public class NonGenericThrows {
    static void test(Exception d) throws RuntimeException {
        throw (RuntimeException) d;
    }

    public static void main(String[] args) {
        NonGenericThrows.test(new SQLException());
    }
}

编译执行:

javac -source 1.7 -target 1.7 NonGenericThrows.java
java NonGenericThrows

结果:

Exception in thread "main" java.lang.ClassCastException: class java.sql.SQLException cannot be cast to class java.lang.RuntimeException (java.sql.SQLException is in module java.sql of loader 'platform'; java.lang.RuntimeException is in module java.base of loader 'bootstrap')
        at NonGenericThrows.test(NonGenericThrows.java:5)
        at NonGenericThrows.main(NonGenericThrows.java:9)

那么为什么通用版本没有给出 ClassCastException ?

我的思维模式哪里出了问题?

java exception generics polymorphism throws
1个回答
0
投票

您将泛型与模板(类似于 C++)混淆了。您提到类型擦除是正确的,顾名思义,它会擦除编译时类型信息的任何痕迹。

您需要使用

Class#cast
来获得所需的行为,但获取
Class<T>
的实例对于您的用例来说并不方便。

© www.soinside.com 2019 - 2024. All rights reserved.