1.1 什么是RTTI?

维基百科的定义:In computer programming, RTTI (Run-Time Type Information, or Run-Time Type Identification) refers to a C++ mechanism that exposes information about an object's data type at runtime. Run-time type information can apply to simple data types, such as integers and characters, or to generic types. This is a C++ specialization of a more general concept called type introspection.

运行时类型信息使得你可以在程序运行时发现和使用类型信息。Runtime type information (RTTI) allows you to discover and use type information while a program is running.

简而言之:当有一个指向基类对象的引用时,使用RTTI可以查询这个引用所引用的对象的确切类型。

在java中可以通过两种方式让我们在运行时识别对象和类的信息:

(1)传统的RTTI:它假设我们在编译时已经知道了所有的类型;

(2)反射机制:它允许我们在运行时发现和使用类的信息。

1.2 为什么需要RTTI?

通常需要知道某个引用类型的变量(为了利用多态的优势,一般是泛化引用,即指向父类的引用变量)所引用的对象的具体类型, 以便根据具体的类型再做具体的不同的操作。使用RTTI可以帮助我们确定泛化引用所引用对象的确切类型。

一般是如下流程:判断引用变量的具体类型 → 转换为具体的类型 → 执行特殊类型相关的操作。

1.3 Java中类型信息在运行时是如何表示的?

这是由Class对象表示的,它包含了与类有关的信息。Java使用Class对象来执行其RTTI,即使你正在执行的是类似转换这样的操作。(Java performs its RTTI using the Class object, even if you’re doing something like a cast.)

2.1 传统的RTTI

严格的说,反射也是一种形式的RTTI,不过,一般的文档资料中把RTTI和反射分开,因为一般的,大家认为RTTI指的是传统的RTTI。

Java中使用RTTI的3种形式(java中已知的RTTI形式)

(1)传统的类型转换

比如“(Type)”,由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,会抛出ClassCastException。在Java中,所有的类型转换都是在运行才进行正确性检查的。所以在运行时需要识别一个对象的类型。注意,C++中类型转换是不会使用RTTI的。

传统的RTTI使用转型或instanceof形式(即以instanceof的形式或isInstance()的形式)实现,但都需要指定要转型的类型,比如:

    public void rtti(Object obj){
Orange orange = (Orange)obj; //其中的obj虽然是被转型了,但在编译期,就需要知道要转成的类型Orange,也就是需要Orange的.class文件
//Class clazz = Class.forName("rtti.Orange"); //相对的,反射完全在运行时在通过Class类来确定类型,不需要提前加载Orange的.class文件。
}

(2)代表对象类型的Class对象

通过查询Class对象可以获取运行时所需的信息。(用了Class对象,不代表就是反射,如果只是用Class对象cast成指定的类,那就还是传统的RTTI)。其实反射和RTTI并没有什么本质的区别,因为java的类都是在运行是加载并解析的,而且两者通过Class对象来获取类型信息。只是RTTI能够维护的类型都是编译时已知的类型,而反射可以使用一些在编译时完全不可知的类型。

        Class clazz = Orange.class;    //获取Class对象,Orange这个类必须是编译时可知的
System.out.println(clazz.getName()); //利用class对应获取各种类型信息
System.out.println(clazz.getTypeName());
System.out.println(clazz.getSuperclass());
System.out.println(clazz.isInterface());

(3)instanceof或Class.isInstance()

传统的RTTI使用转型或instanceof形式(即以instanceof的形式或isInstance()的形式)实现,但都需要指定要转型的类型,比如:

        if(x instanceof Apple){    //Apple这个类必须是编译时可知的,编译器在编译时会去打开和检查Apple对应的.class文件
((Apple)x).info(); } x.getClass().isInstance(apple);//声明apple对象的类必须是编译时可知的

2.2 RTTI与反射的区别

使用RTTI必须满足一个条件:如果想知道泛化引用的确切类型,那么这个类在编译时必须可知。

通过RTTI可以查询到某个对象的确切类型,这个类型在编译时必须已知(要么是系统类库中的类,要么是你自己在代码中定义的类,因为一个Class定义最终会转换成一个.class文件,所以编译器会去查找看有没有对应的.class文件,没有的话在编译时就报错“错误:找不到符号”,这个过程是在编译阶段完成的),这样才能使用RTTI识别它。换句话说,在编译时,编译器必须知道所有要通过RTTI来处理的类。

RTTI与反射的区别如下:

RTTI:由编译器在编译时打开和检查*.class文件。

反射机制:由JVM在运行时打开和检查*.class文件。

            Class clazz1 = Class.forName("rtti.Apple");    //在编译阶段编译器不会检查和打开字符串"rtti.Apple"指定的类对应的.class文件,而是在运行期间由JVM加载。
System.out.println(clazz1.getName());
        Fruit fruit = new Bnana();    //编译阶段编译器会去查找Fruit类和Apple类各自对应的.class文件。
Class clazz2 = fruit.getClass();
System.out.println(clazz2.getName());

疑问:编译器在编译时打开和检查*.class文件的这一过程中具体都干了什么?

3.1 反射机制

维基百科的定义:In computer science, reflection is the ability of a computer program to examine (see type introspection) and modify the structure and behavior (specifically the values, meta-data, properties and functions) of the program at runtime.

并不是所有的类型都能在编译的时候确定下来(比如有输入一个类名显示出这个类的所有方法的程序),所以得把打开和检查.class文件的工作推到运行时再处理。典型的场景是“基于构件的编程”和远程方法调用(RMI) 。

Class.forName()生成的结果在编译时是不可知的,也就是说,编译时不会去验证参数字符串对应的类是否存在。这都是在运行的时候由JVM处理的,所以这个方法会抛出ClassNotFoundException。

Class类支持反射,是在java.lang.reflect中包含了Field/Method/Constructor类,每个类都实现了Member接口。这些类型的对象都是由JVM在运行时创建的,用来表示未知类里对应的成员。如可以用Constructor类创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。同时,还可以调用getFields()、getMethods()、getConstructors()等方法来返回表示字段、方法以及构造器的对象数组。这样,未知的对象的类信息在运行时就能被完全确定下来,而在编译时不需要知道任何信息。

3.2 如何获取Class对象

(1)Class.forName(String packageNamePlusClassName);

(2)Object.getClass();

(3)类字面常量

3.3泛化的Class引用

(1)通配符方式

Class<?> intClass  = int.class;

(2)extends实现范围限定

Class<? extends NUmber> bounded = int.class;

(3)super方式

Class<Apple> apClass = Apple.class;
Apple apple = apClass.newInstance();
Class<? super Fruit> up = apClass.getSuperclass();

3.4 instanceof与class的等价性

(1)instanceof 与 isInstance()生成的结果完全一样,equal与==也一样。

(2)Instanceof与isInstance()保持了类型的概念,它指的是“你是这个类,或者是这个类的派生类吗?”

(3)equal与==比较实际的Class对象,没有考虑继承——它或者是这个确切的类型,或者不是。

4.总结

JAVA编程思想,第14章末尾的总结一节的概括:

第1段的意思,使用RTTI可以发现引用变量的确切类型,然后根据引用变量具体的确切类型执行对应的操作(类似switch语句,P327的例子)。这种方式就没有使用多态,失去了多态的价值。所以尽量使用多态机制,只是在必需的时候才使用RTTI。

第2-4段,概述了RTTI在部分场景下的优势,分别举例说明使用RTTI可以解决的问题。

参考资料

JAVA编程思想,第14章,第8章 8.5.2

http://www.cnblogs.com/zhguang/p/3091378.htm

http://blog.csdn.net/cannel_2020/article/details/7226108

http://blog.csdn.net/a81895898/article/details/8457623

http://blog.sina.com.cn/s/blog_548c8a8301013j6u.html

Java RTTI机制与反射机制的更多相关文章

  1. Java进阶之reflection(反射机制)——反射概念与基础

    反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...

  2. java的泛型与反射机制

    什么是泛型? 泛型,即“参数化类型”.顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参) ...

  3. Java 核心类库之反射机制

    1:什么是反射机制? 2:反射机制它可以做什么呢? 3:反射机制对应的API又是什么? 1):通过反射机制来获取一个对象的全限定名称(完整包名),和类名: 2):实例化Class对象 3):获取对象的 ...

  4. java.lang.Class<T> -- 反射机制

    1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...

  5. 在JAVA中,关于反射机制的讨论

    一.什么是反射机制         简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,     那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制 ...

  6. java工厂类与反射机制

    java 简单工厂类 2012-04-22 15:44:07|  分类: java |  标签:java工厂类  简单工厂类  |举报|字号 订阅     简单工厂模式需要由以下角色组成: 接口    ...

  7. Java SE之初探反射机制

    [Keywords]:Java,Hibernate,虚拟机,框架,SQL [Abstract]:   反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到 ...

  8. JAVA(五)反射机制/Annotation

    成鹏致远 | lcw.cnblog.com |2014-02-04 反射机制 1.认识Class类 在正常情况下,必须知道一个类的完整路径之后才可以实例化对象,但是在 java中也允许通过一个对象来找 ...

  9. java 类加载机制和反射机制

    一.类的加载机制 jvm把class文件加载到内存,并对数据进行校验.解析和初始化,最终形成jvm可以直接使用的java类型的过程.(1)加载         将class文件字节码内容加载到内存中, ...

随机推荐

  1. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...

  2. js,onblur后下一个控件获取焦点判断、html当前活跃控件、jquery版本查看、jquery查看浏览器版本、setTimeout&setInterval

    需求: input控件在失去焦点后直接做验证,验证通不过的话,显示相应错误.但是如果失去焦点后点击的下个控件是比较特殊的控件(比如,退出系统),那么不执行验证操作,直接退出系统(防止在系统退出前,还显 ...

  3. maven spring profile 协同

    请在网上查相关的使用情景,这里直接上要点.另外,可能不只一种方法,但这里只有一种. 1.POM.XML片段,使web.xml文件中有关活跃spring profile的内容可以被maven自动替换 & ...

  4. 纯手工打造漂亮的瀑布流,五大插件一个都不少Bootstrap+jQuery+Masonry+imagesLoaded+Lightbox!

    前两天写的文章<纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身!>受到很多网友的喜爱,今天特别推出姊妹篇<纯手工打造漂亮的瀑 ...

  5. Oracle 常用操作【01】修改、更新数据

    1. oracle 修改表名.列名.字段类型.添加表列.删除表列  alert table scott.test rename to test1--修改表名 alter table scott.tes ...

  6. 如何在前台脚本通过json传递数据到后台(使用微软自带的ajax)

    首先,我们要在前台引入json的脚本,以便于把js对象序列化 <script type="text/javascript" src="/js/jquery.json ...

  7. Infer.net 开源组件: 1, 机器学习入门,要从贝叶斯说起

    我的入门方式,先从应用现象中,总结规律反推本质.一头扎进理论书籍是不对的. 老外的先进,还是体现在传承方面.没办法,我们竞争压力大,有好东西藏着掖着.大家都苦逼 我最开始是从介绍,有了基本概念,见xx ...

  8. 项目分享二:APP 小红点中数字的处理

    小红点,是 APP 中最常见的一个功能,我们先来看一下面的案例,下图中,待评价的商品有 2 个,点击“评价晒单”按钮进行评价后,那么待评价数量应该变成 1,那么这个功能是如何去实现的呢? 一般来说,实 ...

  9. Angular指令1

    Angular的指令 也就是directive,其实就是一WebComponent,以前端的眼光来看,好象很复杂,但是以后端的眼光来看,还是非常简单的.其实就是一个中等水平的类. var myModu ...

  10. JavaScript的理解记录(1)

    1.JavaScript的数据类型分为两类:原始类型和对象类型: 原始类型包括:数字,字符串,布尔值,null和undefined; (都是不可变类型,值不可以修改) 对象类型:普通对象和函数: 函数 ...