一道关于泛型的题目

先看题目:

public class Mocker<T extends Exception> {

    private void pleaseThrow(final Exception t) throws T {
        throw (T) t;
    }

    public static void main(final String[] args) {
        //原题
        try {
            new Mocker<RuntimeException>().pleaseThrow(new SQLException());
        } catch (final SQLException ex) {
            ex.printStackTrace();
        }
    }

}

问,这段代码会出现什么错误?

a.编译错误,因为没有SQLException被抛出

b.抛出ClassCastException,因为SQLException并不是RuntimeException的一个实例

c.没有错误,程序打印出抛出的SQLException堆栈跟踪信息

d.编译错误,因为我们不能将SQLException类型转换成RuntimeException

首先,我们知道,RuntimeException和SQLException都继承自Exception,但是在这个代码中RuntimeException是未检查的异常, 而SQLException是受检异常。

Java的泛型并不是具体化的。这意味着在编译时,泛型的类型信息会“丢失”,并且泛型参数像是被它的限定类型替换了一样, 或者当限定类型不存在时,泛型参数被替换成了Object。这就是大家所说的类型“擦除”。

通常我们会想,第七行会产生一个编译错误,因为我们不能将SQLException转换成RuntimeException, 但是这并不会发生。发生的是将T替换成了Exception,因为我们有:

throw (Exception) t;

pleaseThrow方法期望一个Exception,T被替换成了Exception,因此类型转换被擦除了,就像没写这个代码一样。

因此不会有类型转换异常,排除b和d选项。

那么,如果代码编译通过了,应该变成这样

private void pleaseThrow(Exception t) throws T {
    throw t;
}

对于不知情的旁观者来说,代码中并没有SQLException,而编译器也是这么认为的。

所以最终答案是a.编译错误,因为没有SQLException被抛出。

然而,SQLException确实是被抛出了,我们需要向编译器证明这一点,我们将异常捕获改成RuntimeException

//改成RuntimeException后
try {
    new Mocker<RuntimeException>().pleaseThrow(new SQLException());
} catch (final RuntimeException ex) {
    ex.printStackTrace();
}

编译没有问题,运行

Exception in thread "main" java.sql.SQLException
    at com.happy.exam.Mocker.main(Mocker.java:97)

最终,虚拟机捕获了该异常,为我们提供了非常有力的证据。

 

转载于:https://my.oschina.net/u/3758884/blog/1608358

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值