一、Class对象
二、类型转换前先做检查
1.instanceof
A instanceof B
instanceof用于比较对象A是不是类型B的实例。但是B只能是具体的命名类型(如Integer之类),不能是Class对象。当程序中出现大量instanceof时,说明你的设计可能存在瑕疵,因为大量的instanceof可能能够用以下的方法解决。
//例子 if(A instanceof Integer) 语句1; if(A instanceof Double) 语句2; ... /*错误,比较类型不能是Class对象。 Class type = ... if(A instanceof type) 语句; */
2.动态的instanceof
A.isInstance(B)
Class.isInstance方法提供了一种动态地测试对象的途径。此时A是Class对象,B是对象。这样就解决了需要大量使用instanceof的问题。
//例子 Class type = ... List<Class<? extends Father>> types = ... M[] a = ... for(Class type : types){ if(type.isInstance(a[0])) 语句; }
3.递归计数
A.isAssignableFrom(B)
递归计数是相对于常规计数而言的。正常计数我们可以用动态的instanceof遍历数组实现对类型的计数。
常规计数做法:
【1】定义一个Map用于存储所有类型以及对应的计数。
【2】遍历所有对象并获取它们的Class对象并与Map的所有对象进行A.isInstance(B)比较,并在Map中计数。
递归计数做法:
递归计数主要通过Class.isAssignableFrom()实现。我们注意到,计数时,如果当前对象是子类,那么它也一定是父类。因此在子类计数的同时,以检查父类的方式递归调用计数函数自身即可。isAssignableFrom()用于检测B是否在以A为基类的继承体系下。
//为某个对象计数,完成计数只需要对每个对象调用此函数即可。 public void countClass(Class<?> type){ 为当前类在Map中计数; Class<?> superClass = type.getSuperClass(); if(superClass != null && baseType.isAssignableFrom(superClass)){ //只要父类在基类的继承体系下 countClass(superClass); //递归计数 } }
三、反射及动态代理
1.反射,以及RTTI与反射的区别
反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
RTTI:在运行时,识别一个对象的类型。但是这个类型在编译时必须已知。
反射:在运行时,识别一个对象的类型。但是这个类型在编译时不可获取。
2.动态代理
(1)什么是代理
代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。
代理模式角色分为 3 种:
角色 | 功能 |
---|---|
抽象主题角色 (Subject) | 定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法 |
真实主题角色 (RealSubject) | 真正实现业务逻辑的类 |
代理主题角色 (Proxy) | 用来代理和封装真实主题 |
(2)动态代理
代理是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。(通常RealSubject与Proxy是耦合在一起的)
动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件。(RealSubject与Proxy不再耦合,修改RealSubject不必修改Proxy)
知识细节查询;
《Java编程思想》14.7-14.8
动态代理