Java 内省机制

一、内省机制概述

        Java中的反射机制是通过名称得到类的方法和对象的成份,对于一切Java类都是适用的,但是有时候使用起来比较麻烦。而JavaBean是一种特殊的Java类,遵守JavaBean的规范,即所有的成员都是私有成员,且每个成员都有公开的读取和设定的方法(getter和setter),且这些方法都遵守命名的规范。就是因为JavaBean有这些的特性,sun推出了一种专门对JavaBean成员进行访问的技术,方便对其的访问,就是内省技术。

        即:通过内省机制(自省机制)可以获取和操作JavaBean中的成员信息(方法,事件和属性)。.

JavaBean规范:

什么是JavaBean:符合某些设计规范的类。使用JavaBean,可避免代码重复问题,起到功能重复使用。

1)类必须使用public修饰
2)必须保证有公共无参数的构造器
3)包含属性(property)的操作手段(getter/setter方法)
JavaBean包含的成员:method方法、event事件或property属性

1、内省和反射有什么区别?

        反射(Reflect)是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。

        内省(IntroSpector)是Java 语言对 Bean 类属性、事件的一种缺省处理方法。内省机制是通过反射来实现的

2、内省机制的作用

用于查看和操作JavaBean中的属性:

     1)获取JavaBean中的每一个属性名/属性类型

     2)通过getter方法获取属性值,通过setter方法给属性设置值

3、内省机制中使用到的核心几个类,列举几个常用方法,具体查看API

     1)java.beans.Introspector

          Introspector相当于一个工具类,提供了一种标准的工具来了解目标JavaBean支持的属性,事件和方法,即一系列取得Bean信息的方法。

    • static BeanInfo getBeanInfo(Class<?> beanClass)

      内省Java Bean并了解其所有属性,暴露的方法和事件。

      static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)

      内省Java bean并了解其属性,暴露的方法,低于给定的“停止”点。

     2)java.beans.BeanInfo接口

          beanInfo接口是对一个Bean的描述,可以通过它取得Bean内部的信息。

     3)java.beans.PropertyDescriptor

          PropertyDescriptor类是对一个Bean属性的描述,它提供了一系列对Bean属性进行操作的方法。

     java.beans.FeatureDescriptor类是PropertyDescriptor,EventSetDescriptor和MethodDescriptor等的常见基类(父类)。

     它支持一些可以为任何内省描述符设置和检索的常见信息

二、demo

public class User {
    private Long id;
    private String username;
    private Integer age;
    private Long account;

    public User() {
    }

    getter,setter,toString 方法
}

1、通过内省机制获取JavaBean属性值和属性设值

    @Test
    public void testIntrospector() throws Exception {
        User user = User.class.newInstance();
        user.setId(111L);
        // 获取JavaBean的描述对象BeanInfo
        //BeanInfo beanInfo = Introspector.getBeanInfo(User.class); // 包含父类的,比如:getClass()
        BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class); // 不包含父类的
        // 获取JavaBean中所有属性的描述器对象PropertyDescriptor
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            // 获取当前属性的名称
            String name = pd.getName();

            if("id".equals(name)){
                // 调用getter方法,获取属性值
                Object value = pd.getReadMethod().invoke(user);
                System.out.println(value); // 111
            }
            if("username".equals(name)){
                // 获取当前属性的数据类型
                Class<?> propertyType = pd.getPropertyType();
                System.out.println(propertyType); //class java.lang.String
                // 调用setter方法,设置属性值
                pd.getWriteMethod().invoke(user,"赵云");
            }
            if("age".equals(name)){
                pd.getWriteMethod().invoke(user,17);
            }
        }
        System.out.println(user); //User{id=null, username='赵云', age=17, account=null}
    }

2、JavaBean与Map之间的相互转换

    //JavaBean对象转Map<String,Object>
    public Map<String,Object> bean2map(Object bean) throws Exception {
        Map<String,Object> map = new HashMap<>();
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            String name = pd.getName();
            Object value = pd.getReadMethod().invoke(bean);
            map.put(name,value);
        }
        return map;
    }
    //Map<String,Object>转JavaBean对象
    public <T> T map2bean(Map<String,Object> map, Class<T> clazz) throws Exception {
        T t = clazz.newInstance();
        BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            Object value = map.get(pd.getName());
            pd.getWriteMethod().invoke(t,value);
        }
        return t;
    }

    @Test
    public void testChange() throws Exception {
        User user = new User();
        user.setUsername("赵云");
        user.setAge(17);

        Map<String, Object> map = bean2map(user);
        System.out.println(map); // {id=null, account=null, age=17, username=赵云}

        map.put("account",1000L);
        Class<User> userClass = User.class;
        User user1 = map2bean(map, userClass);
        System.out.println(user1);// User{id=null, username='赵云', age=17, account=1000}
    }

总结:

       1、使用内省机制对JavaBean属性进行操作还是很复杂的,一些第三方组织封装了某些工具类来方便开发者使用,如:

org.apache.commons.beanutils.BeanUtils是apache封装的工具类,用来解决使用内省机制繁琐的问题,包含了挺多方法。

使用时要导入两个包:commons-beanutils-xx.jar和commons-logging-xx.jar。

       2、将 Java的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目或者框架都是采取这两种技术来实现其核心功能。比如Struts2,SpringMVC。

       这些框架只要在.action中,或者controller方法的形参处,引入JavaBean就可以实例化这个JavaBean的值,并且可以获得表单提交的数据,那么它究竟是怎么得到的呢?

       其实就是 request.getParameterMap() 获取得到表单提交来的所有键值对,只不过框架内部封装了,然后框架内部利用内省,将数据封装到JavaBean中。

      3、Java的反射以及内省机制重点掌握,查阅框架源码时多加留意,理解其中的设计重构封装等思想

 

     站在前辈的肩膀上,每天进步一点点

ends~

发布了248 篇原创文章 · 获赞 59 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/100728642