🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### [向下转型与运行时类型信息](https://lingcoder.gitee.io/onjava8/#/book/09-Polymorphism?id=%e5%90%91%e4%b8%8b%e8%bd%ac%e5%9e%8b%e4%b8%8e%e8%bf%90%e8%a1%8c%e6%97%b6%e7%b1%bb%e5%9e%8b%e4%bf%a1%e6%81%af) 由于向上转型(在继承层次中向上移动)会丢失具体的类型信息,那么为了重新获取类型信息,就需要在继承层次中向下移动,使用*向下转型*。 向上转型永远是安全的,因为基类不会具有比派生类更多的接口。因此,每条发送给基类接口的消息都能被接收。但是对于向下转型,你无法知道一个形状是圆,它有可能是三角形、正方形或其他一些类型。 为了解决这个问题,必须得有某种方法确保向下转型是正确的,防止意外转型到一个错误类型,进而发送对象无法接收的消息。这么做是不安全的。 在某些语言中(如 C++),必须执行一个特殊的操作来获得安全的向下转型,但是在 Java 中,每次转型都会被检查!所以即使只是进行一次普通的加括号形式的类型转换,在运行时这个转换仍会被检查,以确保它的确是希望的那种类型。如果不是,就会得到 ClassCastException (类转型异常)。这种在运行时检查类型的行为称作运行时类型信息。下面例子展示了 RTTI 的行为: ~~~ // polymorphism/RTTI.java // Downcasting & Runtime type information (RTTI) // {ThrowsException} class Useful { public void f() {} public void g() {} } class MoreUseful extends Useful { @Override public void f() {} @Override public void g() {} public void u() {} public void v() {} public void w() {} } public class RTTI { public static void main(String[] args) { Useful[] x = { new Useful(), new MoreUseful() }; x[0].f(); x[1].g(); // Compile time: method not found in Useful: //- x[1].u(); ((MoreUseful) x[1]).u(); // Downcast/RTTI ((MoreUseful) x[0]).u(); // Exception thrown } } ~~~ 输出: ~~~ Exception in thread "main" java.lang.ClassCastException: Useful cannot be cast to MoreUseful at RTTI.main ~~~ 正如前面类图所示,**MoreUseful**扩展了**Useful**的接口。而**MoreUseful**也继承了**Useful**,所以它可以向上转型为**Useful**。在`main()`方法中可以看到这种情况的发生。因为两个对象都是**Useful**类型,所以对它们都可以调用`f()`和`g()`方法。如果试图调用`u()`方法(只存在于**MoreUseful**中),就会得到编译时错误信息。 为了访问**MoreUseful**对象的扩展接口,就得尝试向下转型。如果转型为正确的类型,就转型成功。否则,就会得到 ClassCastException 异常。你不必为这个异常编写任何特殊代码,因为它指出了程序员在程序的任何地方都可能犯的错误。\*\*{ThrowsException}\*\* 注释标签告知本书的构建系统:在运行程序时,预期抛出一个异常。 RTTI 不仅仅包括简单的转型。例如,它还提供了一种方法,使你可以在试图向下转型前检查所要处理的类型。“类型信息”一章中会详细阐述运行时类型信息的方方面面。