Java反射 PropertyDescriptor类案例详解

JAVA中反射机制(JavaBean的内省与BeanUtils库)

内省(Introspector) 是Java 语言对JavaBean类属性、事件的一种缺省处理方法。
JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。
例如类UserInfo :

package com.peidasoft.instrospector;  

public class UserInfo {  

    private long userId;
    private String userName;
    private int age;
    private String emailAddress;  

    public long getUserId() {
        return userId;
    }  

    public void setUserId(long userId) {
        this.userId = userId;
    }  

    public String getUserName() {
        return userName;
    }  

    public void setUserName(String userName) {
        this.userName = userName;
    }  

    public int getAge() {
        return age;
    }  

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

    public String getEmailAddress() {
        return emailAddress;
    }  

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
}

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

JDK内省类库:

PropertyDescriptor类:(属性描述器)
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:

  1. getPropertyType(),获得属性的Class对象;
  2. getReadMethod(),获得用于读取属性值的方法;
  3. getWriteMethod(),获得用于写入属性值的方法;
  4. hashCode(),获取对象的哈希值;
  5. setReadMethod(Method readMethod),设置用于读取属性值的方法;
  6. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。

实例代码如下:

package com.peidasoft.instrospector;  

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

public class BeanInfoUtil {  

    // 设置bean的某个属性值
    public static void setProperty(UserInfo userInfo, String userName) throws Exception {
        // 获取bean的某个属性的描述符
        PropertyDescriptor propDesc = new PropertyDescriptor(userName, UserInfo.class);
        // 获得用于写入属性值的方法
        Method methodSetUserName = propDesc.getWriteMethod();
        // 写入属性值
        methodSetUserName.invoke(userInfo, "wong");
        System.out.println("set userName:" + userInfo.getUserName());
    }  

    // 获取bean的某个属性值
    public static void getProperty(UserInfo userInfo, String userName) throws Exception {
        // 获取Bean的某个属性的描述符
        PropertyDescriptor proDescriptor = new PropertyDescriptor(userName, UserInfo.class);
        // 获得用于读取属性值的方法
        Method methodGetUserName = proDescriptor.getReadMethod();
        // 读取属性值
        Object objUserName = methodGetUserName.invoke(userInfo);
        System.out.println("get userName:" + objUserName.toString());
    }
}

Introspector类:

将JavaBean中的属性封装起来进行操作。在程序把一个类当做JavaBean来看,就是调用Introspector.getBeanInfo()方法,得到的BeanInfo对象封装了把这个类当做JavaBean看的结果信息,即属性的信息。
getPropertyDescriptors(),获得属性的描述,可以采用遍历BeanInfo的方法,来查找、设置类的属性。具体代码如下:

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

public class BeanInfoUtil {  

    // 通过内省设置bean的某个属性值
    public static void setPropertyByIntrospector(UserInfo userInfo, String userName) throws Exception {
        // 获取bean信息
        BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);
        // 获取bean的所有属性列表
        PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
        // 遍历属性列表,查找指定的属性
        if (proDescrtptors != null && proDescrtptors.length > 0) {
            for (PropertyDescriptor propDesc : proDescrtptors) {
                // 找到则写入属性值
                if (propDesc.getName().equals(userName)) {
                    Method methodSetUserName = propDesc.getWriteMethod();
                    methodSetUserName.invoke(userInfo, "alan");  // 写入属性值
                    System.out.println("set userName:" + userInfo.getUserName());
                    break;
                }
            }
        }
    }  

    // 通过内省获取bean的某个属性值
    public static void getPropertyByIntrospector(UserInfo userInfo, String userName) throws Exception {
        BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);
        PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
        if (proDescrtptors != null && proDescrtptors.length > 0) {
            for (PropertyDescriptor propDesc : proDescrtptors) {
                if (propDesc.getName().equals(userName)) {
                    Method methodGetUserName = propDesc.getReadMethod();
                    Object objUserName = methodGetUserName.invoke(userInfo);
                    System.out.println("get userName:" + objUserName.toString());
                    break;
                }
            }
        }
    }
}

通过这两个类的比较可以看出,都是需要获得PropertyDescriptor,只是方式不一样:前者通过创建对象直接获得,后者需要遍历,所以使用PropertyDescriptor类更加方便。

package com.peidasoft.instrospector;  

public class BeanInfoTest {  

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("peida");
        try {
            BeanInfoUtil.getProperty(userInfo, "userName");
            BeanInfoUtil.setProperty(userInfo, "userName");
            BeanInfoUtil.getProperty(userInfo, "userName");
            BeanInfoUtil.setPropertyByIntrospector(userInfo, "userName");
            BeanInfoUtil.getPropertyByIntrospector(userInfo, "userName");
            BeanInfoUtil.setProperty(userInfo, "age");  // IllegalArgumentException
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果:

get userName:peida 
set userName:wong 
get userName:wong 
set userName:alan 
get userName:alan 
java.lang.IllegalArgumentException: argument type mismatch 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at com.peidasoft.instrospector.BeanInfoUtil.setProperty(BeanInfoUtil.java:22) 
    at com.peidasoft.instrospector.BeanInfoTest.main(BeanInfoTest.java:26)

说明:BeanInfoUtil.setProperty(userInfo,”age”);报错是应为age属性是int数据类型,而setProperty方法里面默认给age属性赋的值是String类型。所以会爆出argument type mismatch参数类型不匹配的错误信息。

 BeanUtils工具包:
由上述可看出,内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
BeanUtils工具包:下载:http://commons.apache.org/beanutils/,注意:应用的时候还需要一个logging包http://commons.apache.org/logging/
使用BeanUtils工具包完成上面的测试代码:

package com.peidasoft.instrospector;  

import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;  

public class BeanInfoTest {  

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("peida");
        try {
            BeanUtils.setProperty(userInfo, "userName", "peida");
            System.out.println("set userName:" + userInfo.getUserName());
            System.out.println("get userName:" + BeanUtils.getProperty(userInfo, "userName"));
            BeanUtils.setProperty(userInfo, "age", 18);
            System.out.println("set age:" + userInfo.getAge());
            System.out.println("get age:" + BeanUtils.getProperty(userInfo, "age"));
            System.out.println("get userName type:" + BeanUtils.getProperty(userInfo, "userName").getClass().getName());
            System.out.println("get age type:" + BeanUtils.getProperty(userInfo, "age").getClass().getName());
            PropertyUtils.setProperty(userInfo, "age", 8);
            System.out.println(PropertyUtils.getProperty(userInfo, "age"));
            System.out.println(PropertyUtils.getProperty(userInfo, "age").getClass().getName());
            PropertyUtils.setProperty(userInfo, "age", "8");  // IllegalArgumentException
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
运行结果:
[java] view plain copy
set userName:peida
get userName:peida
set age:18
get age:18
get userName type:java.lang.String
get age type:java.lang.String  

java.lang.Integer
Exception in thread "main" java.lang.IllegalArgumentException: Cannot invoke com.peidasoft.instrospector.UserInfo.setAge on bean class
    'class com.peidasoft.instrospector.UserInfo' - argument type mismatch - had objects of type "java.lang.String" but expected signature "int"
    at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2181)
    at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2097)
    at org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1903)
    at org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2010)
    at org.apache.commons.beanutils.PropertyUtils.setProperty(PropertyUtils.java:896)
    at com.peidasoft.instrospector.BeanInfoTest.main(BeanInfoTest.java:32)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2116)
    ... 5 more

说明:
1. 获得属性的值,例如,BeanUtils.getProperty(userInfo, “userName”),返回字符串。
2. 设置属性的值,例如,BeanUtils.setProperty(userInfo, “age”, 8),参数是字符串或基本类型自动包装。设置属性的值是字符串,获得的值也是字符串,不是基本类型。   3. BeanUtils的特点:
1). 对基本数据类型的属性的操作:在WEB开发、使用中,录入和显示时,值会被转换成字符串,但底层运算用的是基本类型,这些类型转到动作由BeanUtils自动完成。
2). 对引用数据类型的属性的操作:首先在类中必须有对象,不能是null,例如,private Date birthday=new Date();。操作的是对象的属性而不是整个对象,例如,BeanUtils.setProperty(userInfo, “birthday.time”, 111111);

package com.peidasoft.Introspector;
import java.util.Date;  

public class UserInfo {  

    private Date birthday = new Date(); // 引用类型的属性,不能为null  

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public Date getBirthday() {
        return birthday;
    }
}
package com.peidasoft.Beanutil;  

import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
import com.peidasoft.Introspector.UserInfo;  

public class BeanUtilTest {
    public static void main(String[] args) {
        UserInfo userInfo=new UserInfo();
         try {
            BeanUtils.setProperty(userInfo, "birthday.time","111111");  // 操作对象的属性,而不是整个对象
            Object obj = BeanUtils.getProperty(userInfo, "birthday.time");
            System.out.println(obj);
        }
         catch (IllegalAccessException e) {
            e.printStackTrace();
        }
         catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

PropertyUtils类和BeanUtils不同在于,运行getProperty、setProperty操作时,没有类型转换,使用属性的原有类型或者包装类。由于age属性的数据类型是int,所以方法PropertyUtils.setProperty(userInfo,”age”, “8”)会爆出数据类型不匹配,无法将值赋给属性。

到此这篇关于Java反射 PropertyDescriptor类案例详解的文章就介绍到这了,更多相关Java反射 PropertyDescriptor类内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java上乘武功入门--反射

    目录 先来看一段魔法吧 反射机制是个什么玩意儿? 构造任意一个类的对象 了解任意一个对象所属的类 了解任意一个类的成员变量和方法 调用任意一个对象的属性和方法 魔法揭秘 总结 先来看一段魔法吧 public class Test { private static void changeStrValue(String str, char[] value) { // 只要执行魔法代码就可以达到下面的效果 // 施展魔法的代码稍后揭秘 } public static void main(String[

  • JAVA编程不能不知道的反射用法总结

    目录 下面对Java反射的基础知识进行说明和总结: 总结 下面对Java反射的基础知识进行说明和总结: 首先定义一个MyBase类,其中有私有字段,也有公有字段.同时也有公有方法和私有方法.MyBase类示例如下: package com.hwdev.demo; /** * 基类示例 * @author wangming */ public class MyBase { //公有字段 public int version = 1; //私有字段 private String date = "20

  • Java反射机制基础详解

    目录 1.什么是Java反射机制? 2.反射机制原理 3.Class类介绍 3.1.Class类基本介绍 3.2.Class类对象的获取方法 Class.forname() 3.3 .可以获取Class对象的类型 4.java反射的作用? 5.反射API主要类 6.Java反射的优缺点 7.反射调用的优化方法 8.反射的基本使用例子 9.反射开放权限操作 总结 1.什么是Java反射机制? 在程序运行中动态地获取类的相关属性,同时调用对象的方法和获取属性,这种机制被称之为Java反射机制 下面给

  • Java开发岗位面试被问到反射怎么办

    目录 到底什么是反射呢??? 2. 类的生命周期 3. Java反射框架主要提供以下功能: 反射的基本用法 1. 获得Class对象 2. 判断是否为某个类的实类 3.创建实例 4. 获取构造器信息 5. 获取方法 6. 获取类的成员变量(字段)信息 7. 利用反射创建数组 反射的注意事项 反射的主要用途 总结 到底什么是反射呢??? 反射的核心就是JVM在运行时才动态加载类或调用方法,访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁. 每一个类都会产生一个对应的Class对象,也

  • java中反射和注解的简单使用方法

    目录 什么反射? Java反射机制提供的功能 反射相关的主要API Class 类 获取Class 类的实例( 四种方法) 哪些类型可以有Class 对象? 演示Class类的常用方法 有了Class对象,能做什么? 调用运行时类的指定结构 1. 调用指定方法 关于setAccessible 调用Class对象的newInstance()方法 综合案例: 注解 什么是注解? 常见的Annotation JDK 中的元注解 自定义 Annotation 最后通过反射获取注解信息: 总结 什么反射?

  • 使用Java反射模拟实现Spring的IoC容器的操作

    目录 实现的功能: 项目结构 下面是程序的项目结构图: 自定义注解 容器实现 测试 实体类User的定义: 实现的功能: 默认情况下将扫描整个项目的文件 可以使用@ComponentScan注解配置扫描路径 只将被@Component注解修饰的类装载到容器中 可以使用@AutoWired注解实现自动装配 读取配置文件中的声明的类并注册到容器中 项目结构 下面是程序的项目结构图: 自定义注解 下面是自定义的三个注解: @AutoWired,@Component,@ComponentScan. @T

  • Java通过反射,如何动态修改注解的某个属性值

    Java反射动态修改注解的某个属性值 昨晚看到一条问题,大意是楼主希望可以动态得建立多个Spring 的定时任务. 这个题目我并不是很熟悉,不过根据题目描述和查阅相关Spring 创建定时任务的资料,发现这也许涉及到通过Java代码动态修改注解的属性值. 今天对此尝试了一番, 发现通过反射来动态修改注解的属性值是可以做到的: 众所周知,java/lang/reflect这个包下面都是Java的反射类和工具. Annotation注解,也是位于这个包里的.注解自从Java 5.0版本引入后,就成为

  • java的反射用不好试试内省?

    目录 Java的内省机制是什么? 使用内省替代直接使用反射可以防止破坏类的封装 总结 Java的内省机制是什么? 内省(Introspection )在心理学中,它是心理学基本研究方法之一.内省法又称自我观察法.它是发生在内部的,我们自己能够意识到的主观现象.也可以说是对于自己的主观经验及其变化的观察.正因为它的主观性,内省法自古以来就成为心理学界长期的争论.争论于它是否客观,是否可靠.另外内省也可看作自我反省,也是儒家强调的自我思考.从这个角度说它可以应用于计算机领域,例如Java内省机制和c

  • Java反射 PropertyDescriptor类案例详解

    JAVA中反射机制(JavaBean的内省与BeanUtils库) 内省(Introspector) 是Java 语言对JavaBean类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则.如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为"值对象"(Value Object),或"VO".方法比较少.这些信息储存在类的私有变量中,通过set(

  • Java基础之枚举Enum类案例详解

    一.文章序言 Java中引用类型:数组.类.接口.枚举.注解 枚举这个既熟悉又陌生的东西具体再哪里可以使用呢? 什么是枚举? 枚举是一个引用类型,枚举就是一个规定了取值范围的变量类型. 枚举变量不能使用其他的数据,只能使用枚举中常量赋值.提高程序安全性: //格式: public enum 枚举名{ //枚举的取值范围 //枚举中可以生命方法 } 枚举的使用场景介绍? 1.最常见的情况如星期,相关变量我们会在Java里面重复使用,在这里我们就可以来定义一个叫做"星期"的枚举. publ

  • Java Condition类案例详解

    一 condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait().notify()实现线程间的协作,相比使用Object的wait().notify(),使用Condition的await().signal()这种方式实现线程间协作更加安全和高效.因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作. Condition是个接口,基本的方法就是await()和signal()方法:

  • Java SoftReference类案例详解

    软引用简介 软引用是用来表示某个引用会被GC(垃圾处理器)收集的类. 当有引用指向某个obj的时候,通常发生GC的时候不会把这个对象处理掉,但是被软引用包装的对象,当应用内存将要被耗尽的时候-->即将发生OOM,垃圾处理器就会把它带走.这么看来,软应用的生命周期还是很长的,可以用来做缓存处理. 我们可以通过以下方式来创建一个软引用: SoftReference<String> ref = new SoftReference<String>("Hello world&

  • java BigDecimal类案例详解

    目录 前言 一.介绍 二.知识点介绍 三.知识点详解 1.概述 2.BigDecimal构造方法 3.源码的描述 4.BigDecimal加减乘除运算 5.总结 6.精炼练习 6.1  题目 6.2 实验步骤 结语 前言 只要认真计划一件事,并且一边坚持一边调整,往往会完成得十分出色.懈怠的情绪谁都会有,不要担心自己比别人走得慢,也不要因暂时的挫折心灰意冷,只要不断调整心态,不停下脚步,最终能抵达终点. 一.介绍 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制

  • Java java.lang.InstantiationException异常案例详解

      java.lang.InstantiationException 是指不能实例化某个对象,一般在我们使用java反射机制去创建某个对象的时候实例化到了一个抽象类或者接口(java中抽象类和接口是不能被实例化),而今天我遇到的则是我在使用反射机制实例化某个持久类的时候爆出这个异常,后来发现是因为iBATIS在对象建立中,会使用不带参数的构造函数来建立对象,而自己的持久化类中含有带参数的构造方法,将默认无参构造方法覆盖,导致在实例化过程出现异常.所以在定义一个无参构造方法可解决. 异常 持久类没

  • Java 反射机制的实例详解

    Java 反射机制的实例详解 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来.那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现. 正文 Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法. 反射

  • java内部测试类代码详解

    我们一般使用的java内部类有4种形式:一般内部类.局部内部类.匿名内部类.静态内部类.以下是我作的一个测试,以说明各种内部类的特性. 有关内部类的特性,代码中有详细说明,如下. /* * java内部类测试 * * InterObj反射结果: * * private int i * private InterObj$InterA ia * public InterObj() * public static void main(java.lang.String[]) * private int

  • Java反射框架Reflections示例详解

    MAVEN 坐标 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.10</version> </dependency> Reflections 的作用 Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据. 获取某个类型的所有

  • java反射方式创建代码详解

    在谈到实例的时候,很多人对这个概念还不能说出所以然.其实实例就是一个具体的对象,像我们之前学习的类.数组都可以创建实例.反射相对而言也是比较抽象的概念,所以我们是能够把它实例化的.下面简单对实例进行了解,然后分别带来无参和有参的反射实例实例化方法. 1.实例说明 new 一个对象是实例,可以把这个new出来的对象叫做实例,说白了就是这个new出来的"东西",叫它对象也可以,叫它实例也可以,对象和实例在这个角度上来讲是等价的. 2.创建空参的实例 使用Class对象的newInstanc

随机推荐