反射和内省的区别
1. 反射
反射其实简单来说就是通过类的名字获得对于这个类的描述,这种描述包括方法、构造器、属性的描述。举个例子来说就是通过类名可以进行实例化对象、对类中的方法的调用、对类中属性的赋值。在许多的框架中反射是经常被应用到的技术,下面举个利用反射进行对象A的属性赋值到对象B。
其中A属性如下
public class A {
private String a;
private String b;
---------get.set方法
}
其中B属性如下,B是继承A的。所以B中也有A种a、b两个变量
public class B extends A{
private String c;
private String d;
---------get.set方法
}
将A中a、b属性的值赋值给B中的a、b两个属性
public class IntrospectorAndReflect {
public static void main(String[] args) throws Exception {
Class classA = Class.forName("Practice.Day05.A"); -- 获得A的Class对象
Class classB = Class.forName("Practice.Day05.B"); -- 获得B的Class对象
A a = (A) classA.newInstance(); -- 实例化A对象
B b = (B) classB.newInstance(); -- 实例化B对象
a.setA("a");
a.setB("b");
fatherToChild(a,b);
System.out.println(b.getA());
}
public static <T>void fatherToChild(T father,T child) throws Exception {
if (child.getClass().getSuperclass()!=father.getClass()){
throw new Exception("child 不是 father 的子类");
}
Class<?> fatherClass = father.getClass(); --通过反射获得Class对象
Field[] declaredFields = fatherClass.getDeclaredFields(); --获得此Class对象的属性信息
for (int i = 0; i < declaredFields.length; i++) {
Field field=declaredFields[i];
//获得属性的get方法
Method method=fatherClass.getDeclaredMethod("get"+upperHeadChar(field.getName()));
Object obj = method.invoke(father);
field.setAccessible(true);--解除方法的私有限定
field.set(child,obj);--执行set方法
}
}
/**
* 首字母大写,in:deleteDate,out:DeleteDate
*/
public static String upperHeadChar(String in) {
String head = in.substring(0, 1);
String out = head.toUpperCase() + in.substring(1, in.length());
return out;
}
}
上面演示了如何通过类的全路径名获得类的Class对象,并且将Class对象进行实例化类的过程。其实这就是反射。其实有时候我们会想,直接new一个对象这么简单的事情,何必要用反射这么麻烦呢?因为反射最大的应用就是动态加载。举个简单的例子如下,现在有A、B两个类,根据运行的需要进行加载不同的类
if (条件1)
加载A类
if (条件2)
加载B类
2. 内省(Introspector)
2.1 内省是什么
内省是什么?我们可以看关于java api文档中的介绍
简单理解就是内省是对于java Bean
的缺省处理,既比如在一个实体类中,有nama、address属性,那么系统会默认在此类中会有get/set方法进行获得和设置这两个值的方法。并且通过上面的介绍可以得知,内省是通过BeanInfo
类进行操作类中的属性和方法的。实例如下:
public class IntrospectorDemo {
public static void main(String[] args) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(A.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
for (PropertyDescriptor x:propertyDescriptors){
System.out.println(x.getName());
System.out.println(x.getReadMethod());
}
System.out.println("-----------------------");
for (MethodDescriptor y:methodDescriptors){
System.out.println(y.getName());
}
}
}
2.2 内省相关类介绍
在内省中常用的类有四个
Introspector
:将JavaBean中
的属性封装起来进行操作。在程序把一个类当做JavaBean
来看,就是调用Introspector.getBeanInfo()
方法,得到的BeanInfo
对象封装了把这个类当做JavaBean
看的结果信息,即属性的信息BeanInfo
:将类中的信息封装到BeanInfo
类中,获得了BeanInfo
对象就相当于获得了类中的所有属性信息。调用getPropertyDescriptors()
方法获得属性描述器,即获得了所有的属性信息。调用PropertyDescriptor
:PropertyDescriptor
实例封装了每个属性特有的一些性质,比如调用getReadMethod()
方法就能获得这个属性的get方法Method,调用getWriteMethod()
方法就能获得这个属性的set方法Method。