Java的RTTI和反射(一)

什么是RTTI?

RTTI的全称是RunTime Type Information的缩写 ,即可以在程序的运行时发现和使用类型信息。在Java里想要在运行时里获得类型的信息有两种方法,一是传统的RTTI即假定我们在编译时已经知道了所有类型,另一种是反射机制,它允许我们在运行时获得类型信息。

为什么需要RTTI?

面向对象编程中的一个基本目的是,让代码只操控一个对基类的引用,这样在添加新类型也能保证不会影响到原来的代码,且增强可读性。比如你有一个Shape类它里面有一个draw()方法,它有三个派生类Circle,Square,Triangle分别覆写了draw方法。

public class Shapes{
    public static void main(String[] args){
        List<Shape> list = Arrays.asList(new Circle,
        new Square,new Triangle());
        for(Shape shape : list)
            shape.draw();
    }
}

但是这样在实际编程的时候经常会有这样的问题,比如我想调用每个子类特有的方法呢?比如Square和Triangle有rotate这个方法,而这个方法Circle没有,这个时候我们就是需要在运行时获得这个shape对象的具体类型信息,来决定是否可以使用某些特定的方法。

Class对象

根据Java的原理,你应该知道编译Java程序的时候,每个你写的类都会编译产生xxx.class文件.如下图:

class

 

这是Java里一个非常强大的特性,Java不像C++这种静态加载语言(即运行前已经加载了所有类型信息),Java则是在开始运行前并非完全加载的,只有在需要对应的类型时才动态加载的。JVM里有一个叫ClassLoader的系统,它会首先检查要用的这个类是否已经被加载,若未加载则会搜索对应的.class文件进行加载。

Java里有Class类,要获得运行时的类型信息,你需要获得它对应的Class对象的应用.

通常有三种方法来获取对应的Class对象引用:

  • 知道类型的具体名字:

Class.forName(String className),这里的className必须是全限定名(也就是相当于文件的据对路径一样,要包含对应的包名才行)。如果用于forName的这个对象没有被加载,就会被自动加载并初始化

  • 有一个具体对象

object.getClass()即可返回对应的Class

  • 类的字面常量

可以用Class myClass = Test.class来直接创建一个Class引用,注意这里和Class.forName()有一个巨大的不同,这里创建的Class引用并不会自动的初始化该对象。并且这种方式创建还有很多好处,这样会使代码更加简洁(因为用Class.forName()可以会抛出ClassNotFoundException,所以它必须写在try/catch里或者抛出异常),而且更安全,因为这样写编译器在编译就可以对其进行检查。

Class类一些常用的方法介绍

  • 获取类型名字

有getName(),getCanonicalName(),getSimpleName()

  • 创建对应类的对象

Class.newInstance()就可以产生对应的对象,注意这里可能会抛出两种异常,一个是IllegalAcessException和InstantiationException,前者主要是可能因为违反了Java里的安全机制如,该类的构筑函数为private。

  • 检查是否是某一类型

有三种方法,一是使用关键字 instanceOf,如可以用 if (circle instanceOf Shape );二是使用Class.isInstance(Object obj)来检查;三是使用xxx.getClass() == xxx.class 来比较检查。在这里一二两种方法完全等价,但是和第三种有巨大不同,一二是相当于问“你是这个类吗,你是这个类的派生类吗”,而方法三就是只最对具体确切的那一个class。

好了,下次再写反射

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>