不学无数的程序员

不学无数的程序员

反射和内省的区别

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()方法获得属性描述器,即获得了所有的属性信息。调用
  • PropertyDescriptorPropertyDescriptor实例封装了每个属性特有的一些性质,比如调用getReadMethod()方法就能获得这个属性的get方法Method,调用getWriteMethod()方法就能获得这个属性的set方法Method。
05-27 14:22