Java内省(Introspector)理解

内省(Introspector) 是Java语言对JavaBean类属性、事件的一种缺省处理方法。

JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object/VO)。这些信息储存在类的私有变量中,通过set()、get()来访问类中的属性。

以下是一个标准的JavaBean:

public class Person {
    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在Person类中有属name,age属性, 我们可以通setName()、getName()方法来得到其值或者设置新的值。通过 setName/getName来访问 userName属性,这就是默认的规则。 Java JDK中提供了一套 API 用来访问某个属性的 getter/setter 方法,这就是内省。

JDK中内省的相关类库:

PropertyDescriptor类:
  PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
      1. getPropertyType(),获得属性的Class对象;
      2. getReadMethod(),获得用于读取属性值的方法;getWriteMethod(),获得用于写入属性值的方法;
      3. hashCode(),获取对象的哈希值;
      4. setReadMethod(Method readMethod),设置用于读取属性值的方法;

      5. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。

使用Java内省操作JavaBean,这是没有任何问题的。但是随之而来的就是编码的复杂度,因此很多第三方类库封装了JavaBean的内省操作,典型的工具包有:BeanUtils工具包(下载地址:http://commons.apache.org/beanutils/)

demo测试代码如下:

public class Person {
    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static void main(String[] args) throws Exception {
        try {
            PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(Person.class).getPropertyDescriptors();
            for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                System.out.printf("属性名:%s%n", propertyDescriptor.getName());
                System.out.printf("属性类型:%s%n", propertyDescriptor.getPropertyType());
                System.out.printf("属性读方法:%s%n", propertyDescriptor.getReadMethod());
                System.out.printf("属性写方法:%s%n", propertyDescriptor.getWriteMethod());
            }
            //测试setProperty()、getProperty()两个方法
            testProperty();
            //测试setPropertyByIntrospector()、getPropertyByIntrospector()两个方法
            testByIntrospector();
            //测试BeanUtils工具包
            testBeanUtils();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置bean的某个属性值
     * @param obj
     * @param propertyName
     * @param value
     * @throws Exception
     */
    private static void setProperty(Object obj,String propertyName,Object value)throws Exception {
        // 获取bean的某个属性的描述符  两种方式
        PropertyDescriptor pd = new PropertyDescriptor(propertyName,obj.getClass());
        // 获得用于写入属性值的方法
        Method setMethod = pd.getWriteMethod();
        System.out.printf("写入方法的方法名:%s%n", setMethod.getName());
        // 写入属性值
        setMethod.invoke(obj, value);
    }

    /**
     * 获取bean的某个属性值
     * @param obj
     * @param propertyName
     * @return
     * @throws Exception
     */
    private static Object getProperty(Object obj,String propertyName) throws Exception {
        // 获取Bean的某个属性的描述符  两种方式
        PropertyDescriptor pd = new PropertyDescriptor(propertyName,obj.getClass());
        // 获得用于读取属性值的方法
        Method getMethod = pd.getReadMethod();
        System.out.printf("读取方法的方法名:%s%n", getMethod.getName());
        // 读取属性值
        return getMethod.invoke(obj);
    }

    /**
     * 通过内省设置bean的某个属性值
     * @param obj
     * @param propertyName
     * @param value
     * @throws Exception
     */
    public static void setPropertyByIntrospector(Object obj, String propertyName, Object value) throws Exception {
        // 获取bean信息
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        // 获取bean的所有属性列表
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        // 遍历属性列表,查找指定的属性
        if (propertyDescriptors != null && propertyDescriptors.length > 0) {
            for (PropertyDescriptor propDesc : propertyDescriptors) {
                // 找到则写入属性值
                if (propDesc.getName().equals(propertyName)) {
                    Method methodSetUserName = propDesc.getWriteMethod();
                    System.out.printf("写入方法的方法名:%s%n", methodSetUserName.getName());
                    // 写入属性值
                    methodSetUserName.invoke(obj, value);
                    break;
                }
            }
        }
    }

    /**
     * 通过内省获取bean的某个属性值
     * @param obj
     * @param propertyName
     * @throws Exception
     */
    public static Object getPropertyByIntrospector(Object obj, String propertyName) throws Exception {
        // 获取bean信息
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        // 获取bean的所有属性列表
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        if (propertyDescriptors != null && propertyDescriptors.length > 0) {
            for (PropertyDescriptor propDesc : propertyDescriptors) {
                // 找到则读取属性值
                if (propDesc.getName().equals(propertyName)) {
                    Method methodGetUserName = propDesc.getReadMethod();
                    System.out.printf("读取方法的方法名:%s%n", methodGetUserName.getName());
                    // 读取属性值
                    Object objUserName = methodGetUserName.invoke(obj);
                    return objUserName;
                }
            }
        }
        return null;
    }

    /**
     * 测试setProperty()、getProperty()两个方法
     * @throws Exception
     */
    public static void testProperty() throws Exception {
        System.out.println("------------------------------华丽的分割线------------------------------");
        Person person = new Person();
        String propertyName = "name";
        Object nameValue = getProperty(person,propertyName);
        System.out.printf("属性name的值=%s%n", nameValue);
        Object name = "张三";
        setProperty(person, propertyName, name);
        System.out.printf("get()获取属性name的值=%s%n", person.getName());
        System.out.printf("getProperty()获取属性name的值=%s%n", getProperty(person, propertyName));
    }

    /**
     * 测试setPropertyByIntrospector()、getPropertyByIntrospector()两个方法
     * @throws Exception
     */
    public static void testByIntrospector() throws Exception {
        System.out.println("------------------------------华丽的分割线------------------------------");
        Person personOther = new Person();
        String propertyAge = "age";
        Object ageValue = getPropertyByIntrospector(personOther,propertyAge);
        System.out.printf("属性age的值=%s%n", ageValue);
        Object age = 20;
        setPropertyByIntrospector(personOther, propertyAge, age);
        System.out.printf("get()获取属性age的值=%s%n", personOther.getAge());
        System.out.printf("getPropertyByIntrospector()获取属性age的值=%s%n", getPropertyByIntrospector(personOther, propertyAge));
    }

    /**
     * 内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
     * 下载地址:http://commons.apache.org/beanutils/
     */
    public static void testBeanUtils() {
        System.out.println("------------------------------华丽的分割线------------------------------");
        Person person = new Person();
        try {
            BeanUtils.setProperty(person, "name", "王五");
            System.out.printf("name:%s%n", BeanUtils.getProperty(person, "name"));
            BeanUtils.setProperty(person, "age", 30);
            System.out.printf("age:%s%n", BeanUtils.getProperty(person, "age"));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/shixuetanlang/article/details/80712803