Java内省机制

Wiki上的解释:

在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。 不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。

内省和反射有什么区别?

        反射是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。 
        内省(IntroSpector)是Java 语言对 Bean 类属性、事件的一种缺省处理方法。 JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性。

        在Java内省中,用到的基本上就是上述几个类。 通过BeanInfo这个类就可以获取到类中的方法和属性。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些 API 存放于包 java.beans 中,一般的做法是通过类 Introspector 的 getBeanInfo方法 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法,这就是内省机制。

JDK内省类库

  • java.beans.Introspector:Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。
  • java.beans.BeanInfo接口:希望提供有关其 bean 的显式信息的 bean 实现者可以提供某个 BeanInfo 类,该类实现此 BeanInfo 接口并提供有关其 bean 的方法、属性、事件等显式信息。
  • java.beans.PropertyDescriptor:PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。

内省代码实现

  • 内省机制单元测试代码
package com.study.java.junit;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Date;

import org.junit.Before;
import org.junit.Test;

import com.study.java.domain.User;

/**
* @Name: IntrospectorTest
* @Description: JavaBean-API:内省机制测试类
* @Author: XXX
* @CreateDate: XXX
* @Version: V1.0
 */
public class IntrospectorTest {

    private User user ;

    @Before
    public void init() {
        user = new User() ;
        user.setName("张三") ;
        user.setAge(21) ;
        user.setGender(true) ;
        user.setBirthday(new Date()) ;
        user.setAddress("北京丰台") ;
    }

    /**
    * @Name: getBeanPropertyInfo
    * @Description: 获取User-Bean的所有属性信息
    * @Author: XXX
    * @Version: V1.0
    * @CreateDate: XXX
    * @Parameters: @throws Exception
    * @Return: void
     */
    @Test
    public void getBeanPropertyInfo() throws Exception {
        //获取User-BeanInfo对象:beanInfo是对一个Bean的描述,可以通过它取得Bean内部的信息
        /**
         * 获取User-BeanInfo对象
         *      1、Introspector类
         *              是一个工具类,提供了一系列取得BeanInfo的方法;
         *      2、BeanInfo接口
         *              对一个JavaBean的描述,可以通过它取得Bean内部的信息;
         *      3、PropertyDescriptor属性描述器类
         *              对一个Bean属性的描述,它提供了一系列对Bean属性进行操作的方法
         */
        BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class) ;
        PropertyDescriptor[] pds = userBeanInfo.getPropertyDescriptors() ;
        for (PropertyDescriptor pd : pds) {
            Method method = pd.getReadMethod() ;
            String methodName = method.getName() ;
            Object result = method.invoke(user) ;
            System.out.println(methodName + "-->" + result);
        }
    }

    /**
    * @Name: getBeanPropertyByName
    * @Description: 获取指定属性名称的属性描述器,并对属性进行操作
    * @Author: XXX
    * @Version: V1.0
    * @CreateDate: XXX
    * @Parameters: 
    * @Return: void
     */
    @Test
    public void getBeanPropertyByName() throws Exception {
        //获取name属性的属性描述器
        PropertyDescriptor pd = new PropertyDescriptor("name", user.getClass()) ;
        //得到name属性的getter方法
        Method readMethod = pd.getReadMethod() ;
        //执行getter方法,获取返回值,即name属性的值
        String result = (String) readMethod.invoke(user) ;
        System.out.println("user.name" + "-->" + result);
        //得到name属性的setter方法
        Method writeMethod = pd.getWriteMethod() ;
        //执行setter方法,修改name属性的值
        writeMethod.invoke(user, "李四") ;
        System.out.println("user.name" + "-->" + user.getName());
    }

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • MyBeanUtils封装工具类
package com.study.java.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Name: MyBeanUtils
 * @Description: JavaBean属性操作工具类
 * @Author: XXX
 * @CreateDate: 2017-3-9 上午10:40:01 
 * @Version: V1.0
 */
public class MyBeanUtils {

    /**
    * @Name: getPropertyValue
    * @Description: 根据指定的属性名称获取属性值
    * @Author: XXX
    * @Version: V1.0
    * @CreateDate: 2017-3-9 上午10:55:17
    * @Parameters: @param propertyName 属性名称
    * @Parameters: @param bean bean实例对象
    * @Return: Object 返回getter方法的返回值,即属性值
     */
    public static Object getPropertyValue(String propertyName, Object bean) {
        Object propertyValue = null ;
        try {
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, bean.getClass()) ;
            Method method = pd.getReadMethod() ;
            propertyValue = method.invoke(bean) ;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return propertyValue ;
    }

    /**
    * @Name: setProperty
    * @Description: 设置/修改属性的内容
    * @Author: XXX
    * @Version: V1.0
    * @CreateDate: 2017-3-9 上午11:01:23
    * @Parameters: @param bean Bean实例对象
    * @Parameters: @param name 属性名
    * @Parameters: @param value 修改内容
    * @Return: void 无
     */
    public static void setProperty(Object bean, String name, Object value) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(name, bean.getClass()) ;
            Method method = pd.getWriteMethod() ;
            method.invoke(bean, value) ;
        } catch (Exception e) {
            e.printStackTrace() ;
        }
    }

    /**
    * @Name: populate
    * @Description: 将Map中的内容封装到JavaBean
    * 说明:
    *   Map中的key必须与JavaBean中的属性名称相同
    *   Map中的value传递给JavaBean对应的属性
    * @Author: XXX
    * @Version: V1.0
    * @CreateDate: XXX
    * @Parameters: @param bean
    * @Parameters: @param map
    * @Return: void
     */
    public static Object populate(Object bean, Map<String, Object> map) {
        if(map != null && map.size() > 0) {
            for(Map.Entry<String, Object> entry : map.entrySet()) {
                String propertyName = entry.getKey() ;
                Object propertyValue = entry.getValue() ;
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(propertyName, bean.getClass()) ;
                    Method method = pd.getWriteMethod() ;
                    method.invoke(bean, propertyValue) ;
                } catch (Exception e) {
                    throw new RuntimeException(e) ;
                }
            }
        } 
        return bean ;
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 工具类单元测试代码
package com.study.java.junit;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import com.study.java.domain.User;
import com.study.java.utils.MyBeanUtils;

/**
* @Name: MyBeanUtilsTest
* @Description: JavaBean属性操作工具测试类
* @Author: XXX
* @CreateDate: XXX
* @Version: V1.0
 */
public class MyBeanUtilsTest {

    private User user ;

    @Before
    public void init() {
        user = new User() ;
        user.setName("张三") ;
        user.setAge(21) ;
        user.setGender(true) ;
        user.setBirthday(new Date()) ;
        user.setAddress("北京丰台") ;
    }

    @Test
    public void testSetPropertyValue() {
        System.out.println(user);
        //设置String类型数据
        MyBeanUtils.setProperty(user, "name", "李思思") ;
        //设置int类型数据
        MyBeanUtils.setProperty(user, "age", 23) ;
        //设置boolean类型数据
        MyBeanUtils.setProperty(user, "gender", false) ;
        //设置Date类型数据
        MyBeanUtils.setProperty(user, "birthday", new Date(13213412412L)) ;
        System.out.println(user);
    }

    @Test
    public void testGetPropertyValue() {
        //获取String类型属性
        String name = (String) MyBeanUtils.getPropertyValue("name", user) ;
        //获取int类型属性
        int age = (int) MyBeanUtils.getPropertyValue("age", user) ;
        //获取boolean类型属性
        boolean gender = (boolean) MyBeanUtils.getPropertyValue("gender", user) ;
        //获取Date类型属性
        Date birthday = (Date) MyBeanUtils.getPropertyValue("birthday", user) ;
        System.out.println(name + "," + age  + "," + gender  + "," + birthday  + ".");
    }

    @Test
    public void testPopulate() {
        //向Map集合中封装数据,适用于request.getParameterMap() ;
        Map<String, Object> map = new HashMap<String, Object>() ;
        map.put("name", "王五") ;
        map.put("age", 21) ;
        map.put("gender", true) ;
        map.put("birthday", new Date(32131412L)) ;
        String[] hobbies = {"打球", "唱歌"} ;
        map.put("hobbies", hobbies) ;
        //将Map集合中的数据封装到UserBean
        User u = (User) MyBeanUtils.populate(new User(), map) ;
        System.out.println(u);
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

总结: 
       由上述可看出,内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。对于该工具包API的作用及使用方法,我将在下一篇文章进行总结,这里先提供下BeanUtils工具包的下载地址:http://commons.apache.org/beanutils/;注意:BeanUtils的包依赖于logging包,logging包的下载地址为:http://commons.apache.org/logging/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值