一、RTTI
RTTI(Run-Time Type Information)指的是运行时类型信息,这让你可以在程序运行时发现和使用类型信息。Java中让我们在运行时识别对象和类的信息的方式主要有两种。
- 传统的"RTTI",假定我们在编译的时候就已经知道了所有的类型信息。
- “反射”机制,允许我们在运行时候发现和使用类型信息。
二、RTTI使用背景
假设和我们定义了Shape, Square, Circle, Triangle.等类,并且后三者继承自Shape。具体使用某个类的时候使用多态调用
Shape sp = new Circle();
sp = new Triangle();
sp = new Square();
一个图形只要增加一个类,而具体调用的地方则不用修改。现在有一个需求:把所有Triangle设置为红色。在只暴露了Shape的引用sp的情况下获得sp具体的类型信息。这是就是RTTI的一个具体的需求,即在运行多态的好处是动态绑定调用方法,只有在执行的时候才知道sp绑定的是哪个具体子类的方法。这种方法的好处是代码跟容易维护和扩展,因为要增加时候发现和使用类型信息。
abstract class Shape{ void draw(){ System.out.println(this+".draw()"); } abstract public String toString(); } class Circle extends Shape{ @Override public String toString() { return "Circle"; } } class Square extends Shape{ static { System.out.println("loading square......"); } @Override public String toString() { return "Square"; } } class Triangle extends Shape{ @Override public String toString() { return "Triangle"; } } public class RTTI { public static void main(String[] args) { Shape sp = new Triangle(); } }
三、RTTI的核心
Java中支持RTTI工作的核心即是Class对象,类型信息是由Class对象所维护的。类是程序的一部分,每一个类都有一个Class对象(保存在.class) 文件之中,在使用一个类生成对象时,java虚拟机会使用类加载器加载Class对象(查找Class文件)。所以获取RTTI就是获取类的Class对象的引用。
常用的获取RTTI的方法
- 知道类的名称
Class<?> p = Class.forName("Inn");//有异常抛出
Class<?> p = Inn.class;//字面常量
- 知道类对象的引用
Class<?> p = sp.getClass();
四、反射:运行时的类信息
在使用传统的RTTI时候有个限制,就是类型在编译时候必须已知,这样传统的RTTI才会识别。即在编译时,编译器必须知道所有要通过RTTI处理的类。
但是现在还有一个需求,假设你获得了一个网络程序的引用,你并不能在编译期间获得对象所属的类。在分布式环境中比较常见。
在Java中支持反射机制的是Class类和java.lang.reflect类库【Field、Method、Constructor】
在Java中支持反射机制的是Class类和java.lang.reflect类库【Field、Method、Constructor】
通过运行时获取Class对象,再通过Field、Method、Constructor获取未知类的属性、普通方法、构造器,从而对这个对象的类进行使用。
简单来说 反射是和未知类型的对象打交道,使用未知对象提供的方法以及获取其属性。
传统RTTI和反射机制的区别是
- 对RTTI来说,在编译期间打开和检查.class文件
- 对反射来说,在运行期间打开和检查.class文件【本地获取或者网络获取】