一、RTTI
RTTI——(Run-Time Type Information)指的是运行时类型信息,这让你可以在**程序运行时发现和使用类型信息。**Java中让我们在运行时识别对象和类的信息的方式(RTTI)主要有两种——
传统的"RTTI"——
假定我们在编译的时候就已经知道了所有的类型信息。
“反射”机制——
允许我们在运行时候发现和使用类型信息。
二、RTTI的核心
Java中支持RTTI工作的核心即是Class对象,类型信息是由Class对象所维护的。
类是程序的一部分,每一个类都有一个Class对象(保存在.class) 文件之中,在使用一个类生成对象时,java虚拟机会使用类加载器加载Class对象(查找Class文件)。
———所以获取RTTI就是获取类的Class对象的引用。
三、反射:运行时的类信息
在使用传统的RTTI时候有个限制,就是类型在编译时候必须已知,**这样传统的RTTI才会识别。**即在编译时,编译器必须知道所有要通过RTTI处理的类。
但是现在还有一个需求,假设你从磁盘或者网络连接中获取了一串字节,并且你被告知这些字节代表了代表一个类,既然这个类在你的程序生成代码之后很久才会出现,那么怎样才能使用这样的类呢?你并不能在编译期间获得对象所属的类。在分布式环境中比较常见。
** 这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。这样你就可以使用Constructor创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。
** 另外,还可以调用getFields0)、getMethodsO)和getConstructors0等很便利的方法,以返回表示字段、方法以及构造器的对象的数组)
这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。
获取反射中的Class对象的三种方法
Class.forName 静态方法
类的.class 方法
实例对象的 getClass() 方法
反射创建类对象主要的两种方式
Class的newInstance()
Constructor的newInstance()
代码示例——
Class<?> clazz = null;
//获取Class对象的引用
clazz = Class.forName("com.example.javabase.User");
//第一种方法,实例化默认构造方法,User必须无参构造函数,否则将抛异常
User user = (User) clazz.newInstance();
user.setAge(20);
user.setName("java");
System.out.println(user);
这段代码则是到整个程序运行的时候,从字符串 “com.example.javabase.User”,才知道要操作的类是 User。
四、普通RTTI和反射之间真正的区别
RTTI和反射之间真正的区别只在于对RTTI来说,编译器在编译时打开和检查.cass文件。(换句话说,我们可以用“普通”方式调用对象的所有方法。)
而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
——对RTTI来说,在编译期间打开和检查.class文件
——对反射来说,在运行期间打开和检查.class文件【本地获取或者网络获取】
五、动态代理——提供对象的对象
代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。
代码示例——
解析——
因为consumer()接受的Interface,所以它无法知道正在获得的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是SimpleProxy已经被插入到了客户端和RealObject之间,因此它会执行作,然后调用RealObiect上相同的方法
六、动态代理
Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。