深圳建设工程交易服务网老网站,品牌官方网站建设需要什么,wordpress关键词描述设置,建设项目备案网站管理系统本章概要
为什么需要 RTTI RTTI#xff08;RunTime Type Information#xff0c;运行时类型信息#xff09;能够在程序运行时发现和使用类型信息 RTTI 把我们从只能在编译期进行面向类型操作的禁锢中解脱了出来#xff0c;并且让我们可以使用某些非常强大的程序。对 RTTI …本章概要
为什么需要 RTTI RTTIRunTime Type Information运行时类型信息能够在程序运行时发现和使用类型信息 RTTI 把我们从只能在编译期进行面向类型操作的禁锢中解脱了出来并且让我们可以使用某些非常强大的程序。对 RTTI 的需要揭示了面向对象设计中许多有趣并且复杂的特性同时也带来了关于如何组织程序的基本问题。
本章将讨论 Java 是如何在运行时识别对象和类信息的。主要有两种方式
“传统的” RTTI假定我们在编译时已经知道了所有的类型“反射”机制允许我们在运行时发现和使用类的信息。
为什么需要 RTTI
下面看一下我们已经很熟悉的一个例子它使用了多态的类层次结构。基类 Shape 是泛化的类型从它派生出了三个具体类 Circle 、Square 和 Triangle见下图所示。 这是一个典型的类层次结构图基类位于顶部派生类向下扩展。面向对象编程的一个基本目的是让代码只操纵对基类(这里即 Shape )的引用。这样如果你想添加一个新类(比如从 Shape 派生出 Rhomboid)来扩展程序就不会影响原来的代码。在这个例子中Shape 接口中动态绑定了 draw() 方法这样做的目的就是让客户端程序员可以使用泛化的 Shape 引用来调用 draw()。draw() 方法在所有派生类里都会被覆盖而且由于它是动态绑定的所以即使通过 Shape 引用来调用它也能产生恰当的行为这就是多态。
因此我们通常会创建一个具体的对象(Circle、Square 或者 Triangle)把它向上转型成 Shape (忽略对象的具体类型)并且在后面的程序中使用 Shape 引用来调用在具体对象中被重载的方法如 draw()。
代码如下
import java.util.stream.*;abstract class Shape {void draw() {System.out.println(this .draw());}Overridepublic abstract String toString();
}class Circle extends Shape {Overridepublic String toString() {return Circle;}
}class Square extends Shape {Overridepublic String toString() {return Square;}
}class Triangle extends Shape {Overridepublic String toString() {return Triangle;}
}public class Shapes {public static void main(String[] args) {Stream.of(new Circle(), new Square(), new Triangle()).forEach(Shape::draw);}
}输出结果 基类中包含 draw() 方法它通过传递 this 参数传递给 System.out.println()间接地使用 toString() 打印类标识符(注意这里将 toString() 声明为 abstract以此强制继承者覆盖该方法并防止对 Shape 的实例化)。如果某个对象出现在字符串表达式中(涉及和字符串对象的表达式)toString() 方法就会被自动调用以生成表示该对象的 String。每个派生类都要覆盖从 Object 继承来的toString() 方法这样 draw() 在不同情况下就打印出不同的消息(多态)。
这个例子中在把 Shape 对象放入 StreamShape 中时就会进行向上转型(隐式)但在向上转型的时候也丢失了这些对象的具体类型。对 stream 而言它们只是 Shape 对象。
严格来说StreamShape 实际上是把放入其中的所有对象都当做 Object 对象来持有只是取元素时会自动将其类型转为 Shape。这也是 RTTI 最基本的使用形式因为在 Java 中所有类型转换的正确性检查都是在运行时进行的。这也正是 RTTI 的含义所在在运行时识别一个对象的类型。
另外在这个例子中类型转换并不彻底Object 被转型为 Shape 而不是 Circle、Square 或者 Triangle。这是因为目前我们只能确保这个 StreamShape 保存的都是 Shape
编译期stream 和 Java 泛型系统确保放入 stream 的都是 Shape 对象Shape 子类的对象也可视为 Shape 的对象否则编译器会报错运行时自动类型转换确保了从 stream 中取出的对象都是 Shape 类型。
接下来就是多态机制的事了Shape 对象实际执行什么样的代码是由引用所指向的具体对象Circle、Square 或者 Triangle决定的。这也符合我们编写代码的一般需求通常我们希望大部分代码尽可能少了解对象的具体类型而是只与对象家族中的一个通用表示打交道本例中即为 Shape。这样代码会更容易写更易读和维护设计也更容易实现更易于理解和修改。所以多态是面向对象的基本目标。
但是有时你会碰到一些编程问题在这些问题中如果你能知道某个泛化引用的具体类型就可以把问题轻松解决。例如假设我们允许用户将某些几何形状高亮显示现在希望找到屏幕上所有高亮显示的三角形或者我们现在需要旋转所有图形但是想跳过圆形(因为圆形旋转没有意义)。这时我们就希望知道 StreamShape 里边的形状具体是什么类型而 Java 实际上也满足了我们的这种需求。使用 RTTI我们可以查询某个 Shape 引用所指向对象的确切类型然后选择或者剔除特例。