• Java 内省 Introspector


    操纵类的属性,有两种方法

    反射

    内省

    面向对象的编程中,对于用户提交过来的数据,要封装成一个javaBean,也就是对象

    其中Bean的属性不是由字段来决定的,而是由get和Set方法来决定的

    public class Person {
    
        private String name ;
        private String password;
        private int age;
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getSex()
        {
            return null;
        }
    }

    对于这个Bean,表面上看来只有三个属性,name,password,age
    但是

    @Test
        public void test() throws Exception
        {
            BeanInfo info = Introspector.getBeanInfo(Person.class);
            PropertyDescriptor[] pds = info.getPropertyDescriptors();
            for(PropertyDescriptor pd:pds){
                System.out.println(pd.getName());
            }
        }

    实际上从结果来看属性会有5个

    age
    class
    name
    password
    sex

    原因呢,就是属性石根据get和Set方法确定的,而所有的类都从Object继承而来,Object本身有一个属性

    public final Class<?> getClass()

    如果不需要父类的属性,有一个重载方法

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


    内省把Bean(相当于对象)的所有属性封装在一个BeanInfo对象里,拿到了BeanInfo就相当于拿到了Bean的所有属性

    得到每一个属性的元数据(是个属性数组)

    得到属性的读方法和写方法

    然后就可以操作读方法或者写方法

    @Test
        public void test() throws Exception
        {
            Person p = new Person();
            PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
            //得到写方法
            Method method = pd.getWriteMethod();
            method.invoke(p,48);
            //得到读方法
            method = pd.getReadMethod();
            System.out.println(method.invoke(p, null));
            
        }

    获取属性类型

    @Test
        public void test() throws Exception
        {
            Person p = new Person();
            PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
            Class c = pd.getPropertyType();
            System.out.println(c);
            
        }


    这上面是Sun公司的一套用法,后来Apache觉得麻烦,就开发了自己的一套用法

    当然,要在Eclipse里引入jar包

    Commons-BeanUtils 提供对 Java 反射和自省API的包装  
    commons-logging 提供了对日志实现的包装,包括log4j,jdk1.4日志类
    一般的项目使用logging 包作为日志工具,Log类地方法记录日志;
    BeanUtils 作bean数据提取和注射
    BeanUtils的使用依赖于日志文件这个知识库,所以两个都要导入

    同时在编写的时候,要导入源码(通过F2)

    public static void main(String[] args) throws IllegalAccessException, InvocationTargetException{
            Person p = new Person();
            BeanUtils.setProperty(p, "age", “11”);        
            System.out.println(p.getName());
        }    


    Person类中的age类型为int,这里给传递一个String是可以的,因为

    BeanUtils支持八种基本数据类型之间的相互转化

    但是如果遇到复杂类型,要注册复杂类型转化器

    比如DateTime类型

    public static void main(String[] args) throws IllegalAccessException, InvocationTargetException{
            Person p = new Person();
            BeanUtils.setProperty(p, "age", 11);
            ConvertUtils.register(new Converter() {            
                @Override
                public Object convert(Class type, Object value) {
                    if(value == null){
                        return null;
                    }
                    if( !(value instanceof String)){
                        throw new ConversionException("只支持String类型数据");
                    }
                    String str = (String)value;
                    if(str.trim().equals("")){
                        return null;
                    }
                    
                    SimpleDateFormat dr = new SimpleDateFormat("yyyy-MM-dd");
                    try{
                        return dr.parse(str);
                    }catch(ParseException e){
                        throw new RuntimeException(e);
                    }
                }
            }, Date.class);
            BeanUtils.setProperty(p, "birthday", "1988-01-14");
            System.out.println(p.getName());
        }    


    看看register方法

    public static void register(Converter converter, Class clazz) {
    
            ConvertUtilsBean.getInstance().register(converter, clazz);
    
        }


    所以要实例化一个转化器

    1.  对new Converter()这里用到了匿名类

    2.  在使用数据value的时候,要检测,再使用

    3.  抛异常:

    try{
        return dr.parse(str);
    }catch(ParseException e){
        throw new RuntimeException(e);
    }

    这一句话中,不能把异常直接抛给父类,因为这个匿名类是子类,是在覆盖父类的方法,子类方法不能抛比父类方法更多的异常,所以一定要抓catch
    也不能使用

    try{
        return dr.parse(str);
    }catch(ParseException e){     
    e.printStackTrace(); }

    这样的话,会把异常直接打印在控制台上,并没有通知上一层,上一层是不知道的,会继续执行

    所有的程序都不是给自己调用的,是给上一层调用的,所以出了问题一定要告诉上一层,不能直接打印在控制台上。

    可以使用map

    同时ConvertUtils已经实现好了一些转换器,如日期转换器

    public class Demo1 {
    
        public static void main(String[] args) throws IllegalAccessException, InvocationTargetException{
            Map map = new HashMap();
            map.put("name", "aaa");
            map.put("password", "123");
            map.put("age", "23");
            map.put("birthday", "1989-01-14");
            
            ConvertUtils.register(new DateLocaleConverter(), Date.class);
            
            Person bean = new Person();
            BeanUtils.populate(bean, map);
        }    
    }
  • 相关阅读:
    一、反射机制介绍_Class 对象获取
    六、.XPATH 技术_快速获取节点
    五、.DOM4J 方式解析 XML 数据
    四、.JDOM 解析 XML 数据
    三、SAX 方式解析 XML 数据
    二、DOM方式解析XML
    一、Schema验证XML
    三、线程同步Synchronized
    二、线程状态
    JDK8Lambda和方法的引用
  • 原文地址:https://www.cnblogs.com/tech-bird/p/3774870.html
Copyright © 2020-2023  润新知