今天在看《Java核心技术》卷一的泛型程序设计章节的时候,提到了通过捕获异常后,然后强制类型转换为RuntimeException类型,达到unchecked异常抛出。不必必须通过try-catch-finally语句来处理异常的目的。但感觉违反了类型强制类型转换的规则。所以思考之。
强制类型转换分两类:基本数据类型的强制类型转换、引用类型的强制类型转换。这里讲下引用类型强制转换。被转换的如果是子类,那么自然而然就可以换;被转换的是父类,那么就需要强制转换,如果父类的引用实际指向的是子类对象,那么转换成功,如果不是转换不成功。
通过这篇文章可以理解得更清晰。同时还看见评论说,这个概念和虚拟机的内存模型一并讲更清晰。
但是现在看下下面这个代码:
package reflect;
import java.io.FileNotFoundException;
public class Main {
public static void main(String[] args) {
new Block() {
@Override
public void body() throws Exception {
throw new FileNotFoundException();
}
}.toThread().start();
}
}
abstract class Block {
public abstract void body() throws Exception;
public Thread toThread() {
return new Thread() {
public void run() {
try {
body();
} catch (Throwable t) {
//将Throwable的异常包装为了RuntimeException
Block.<RuntimeException>throwAs(t);
}
}
};
}
@SuppressWarnings("unchecked")
public static <T extends Throwable> void throwAs(Throwable e) throws T {
throw (T) e;
}
}
这个地方body抛出的是,一个FileNotFoundException,它可以转换为Throwable,因为Throwable是它的父类。但是在catch语句中把他强制转换为RuntimeException是不行的。因为RuntimeException不是FileNotFoundException的父类。那怎么程序可以通过呢?
其实我理解的这里的道理就是编译器被欺骗了:
- 当泛型申明为RuntimeException时,编译器就认为这是一个不需要捕获的异常,
- 实际代码执行的过程中,由于擦除的关系,擦除后T被Throwable代替。在运行时强制转换又不会出问题。
数组的强制类型转换是一样的
Object obj1[] = {"t1","t2"}; //第一个数组
Object obj2[] = new String[]{"t1","t2"};//第二个数组
这里需要注意一个问题就是,基本数据类型的数组不能强制转换为Object[]数组,因为基本数据类型不是继承于Object的。
int[] i = new int[]{1,3,4};
//Cannot cast from int[] to Object[]
//Object[] objects = (Object[])i;
数组的类型取决于初始化的时候是什么,而不是取决于数组内部装的是什么类型的。 数组的类型确定了之后,数组可以装的对象的大类型就确定了,只能是数组的类型或者其子类型。 所以,第一个数组的类型就是Object,他是不能向下转型为String。 第二个数组的类型是String(虽然申明是Object,但是实际是String),所以他可以向下转型为String[]类型。