Java运行时类型信息RTTI

应用程序在运行的时候获取一个对象的类型信息的技术称之为运行时类型信息RTTI(Run-Time Type Identification)。RTTI是C++的一个概念,Java中的RTTI是在《think in java》这本书中作者提出来的,官方文档里面并没有RTTI这个概念。作为学习者不应该纠结于一项技术的命名,而应该关注命名所指代的具体技术或者思想,RTTI指代的是一组在运行时获取对象类型信息的方法。

为什么要在运行时获取一个对象的类型信息?

抽象编程通过基类对象来操作子类对象,怎么把基类对象转换为子类对象?考虑下面示例代码,怎么把animal对象转换为Cat或者Dog对象:

class Animal{ }
class Pet extends Animal{}
class Dog extends Pet{ }
class Cat extends Pet{ }
public class Test {
    /**
     * 随机创建Dog或Cat对象,共10个。
     */
    static ArrayList<Animal> randomCreate() {
        ArrayList<Animal> animals = new ArrayList<>();
        Random r = new Random();
        for (int i=0; i<10; i++) {
            int num = Math.abs(r.nextInt()) % 2;
            if (num == 0)
                animals.add(new Dog());
            else
                animals.add(new Cat());
        }
        return animals;
    }
    public static void main(String[] args) {
        ArrayList<Animal> animals = randomCreate();
        for (Animal animal : animals) {
            //怎么把animal转换为Cat或者Dog?
        }
    }
}

由于我们是随机创建Cat或者Dog对象,在for循环无法判断animal对象到底是Cat还是Dog,这时就需要获取对象的类型信息,根据类型信息把animal对象转换为Cat或者Dog对象。

回到问题,为什么要在运行时获取一个对象的类型信息?答案是为了类型转换,在实际开发过程中会遇到需要把基类对象转换为某个子类对象,而我们不知道基类对象所引用的对象是否真的属于这个子类,通过RTTI我们可以检测对象的具体类型然后进行转换。

获取类型信息

有三种方法可以在运行时获取类型信息:

  • instanceof 关键字
  • Class类的isInstance方法
  • 使用equal方法比较Class是否一致

使用instanceof关键字获取类型信息使用示例如下:

ArrayList<Animal> animals = randomCreate();
for (Animal animal : animals) {
    if (animal instanceof  Dog) {
        Dog d = (Dog) animal;
    }
    if (animal instanceof  Cat) {
        Cat c = (Cat) animal;
    }
}

Class类的isInstance方法使用示例如下:

ArrayList<Animal> animals = randomCreate();
for (Animal animal : animals) {
    if (Dog.class.isInstance(animal)) {
        Dog d = (Dog) animal;
    }
    if (Cat.class.isInstance(animal)) {
        Cat c = (Cat) animal;
    }
}

使用equal方法比较Class是否一致使用示例如下:

ArrayList<Animal> animals = randomCreate();
for (Animal animal : animals) {
    // 也可以使用==进行比较:Dog.class == animal.getClass()
    if (Dog.class.equals(animal.getClass())) {
        Dog d = (Dog) animal;
    }
    if (Cat.class.equals(animal.getClass())) {
        Cat c = (Cat) animal;
    }
}

instanceof关键字和isInstance方法功能上完全一模一样,下文使用instanceof指代。equals和==功能上也是一模一样,下文使用equals指代。instanceof和equals的区别在于,instanceof考虑了继承,可以判断一个对象是否派生于某个类。而equals则没有考虑继承,它只能判断对象是不是某个确切的类型。示例如下:

Animal dog = new Dog();
if (dog instanceof Pet){
    System.out.println("dog instanceof Pet => true");
} else {
    System.out.println("dog instanceof Pet => false");
}

if (dog.getClass().equals(Pet.class)){
    System.out.println("dog.getClass().equals(Pet.class) => true");
} else {
    System.out.println("dog.getClass().equals(Pet.class) => false");
}
/*程序输出
dog instanceof Pet => true
dog.getClass().equals(Pet.class) => false
*/

最后

抽象编程通过基类来操作子类对象,使模块依赖于基类,从而降低模块之间的耦合性,如果使用RTTI将使模块间的耦合性变高,所以当应用程序需要使用RTTI技术时,应该考虑是否设计出了问题,是否必须使用RTTI。

 

【水煮Java】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值