Java内省机制

内省和反射有什么区别?

反射是在运行状态把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());
}

}
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 ;
}

}
工具类单元测试代码
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);
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值