以下笔记是根据张孝祥的视频整理而成!
内省API、JavaBean、BeanUtils工具的使用
一、内省API
1、什么是JavaBen
Javabean是一种特殊的java类,主要用来传递数据信息的,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如下程序所示就表示一个JavaBean;
package com.wisdragon.introspector;
import java.util.Date;
/**
* 描述: 建立一个JavaBean
*/
public class Student {
private String name;
private int age;
// private Date birthday;
private Date birthday = new Date();
public Student() {
super();
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return this.name + ":" + this.age;
}
}
从以上的类中可以看出,在程序中使用setter和getter方法来访问类的私有属性。那么怎么判断类中的属性呢?以上程序中name和age属性都已用private进行封装,对于外界是透明的。因此,不能认为name和age就是此类的属性,判断类的属性需要从getter和setter方法入手。观察下面的setAge()方法
public void setAge(int age) {
this.age = age;
}
setAge()看做设置age值,因此age才是此类的属性。
如以下的程序所示: 类中的属性是count,而不是num。
public class Ball {
private int num;
public void setCount(int count){
this.num = count;
}
}
2、什么是内省
内省是JDK提供的一套用户操作JavaBean的API。这些API位于java.beans包中。
如果给你一个属性名(假设为name),需要你通过这个属性名获取这个属性的值,该怎么做?
普通流程: name --> getName()
此处属性变get或set有一定的要求,如果属性名的第二个字母为小写,则将第一个字母变为大写(name-->Name),如果第二个字母为大写,则不需要变化。(CPU-->CPU) 。
使用内省API: 获取该属性的getter或setter方法,使用反射的invoke()执行方法。
要使用内省,则需要学习以下的API:
public class PropertyDescriptor extends FeatureDescriptor -----描述 Java Bean 通过一对存储器方法导出的一个属性 |
构造方法:publicPropertyDescriptor(String propertyName,Class<?> beanClass) throwsIntrospectionException |
主要的方法: |
1、public Method getReadMethod() ------- 获得应该用于读取属性值的方法。 |
2、public Method getWriteMethod() ------- 获得应该用于写入属性值的方法。 |
范例:使用内省API完成对Student类中属性的操作
package com.wisdragon.introspector;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class IntroSpectorDemo1 {
public static void main(String[] args)throws Exception{
Student student = new Student("黄玉泽", 22);
//简单的方式
String propertyName = "name"; //属性名
PropertyDescriptor pd = new PropertyDescriptor(propertyName, Student.class);
/*
* PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
*/
//取值
Method method1 = pd.getReadMethod();
Object retVal = method1.invoke(student, null);
System.out.println(retVal);
//设置值
String property = "age";
PropertyDescriptor p = new PropertyDescriptor(property, Student.class);
Method m = p.getWriteMethod();
m.invoke(student, 23);
System.out.println(student.toString());
}
结果:
黄玉泽
黄玉泽 :23对于以上的程序还可以使用第二种方式实现:
范例: 使用Instrospector 实现同样的功能
package com.wisdragon.introspector;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class IntroSpectorDemo1 {
public static void main(String[] args)throws Exception{
Student student = new Student("黄玉泽", 22);
//采用更为复杂的方式,完成以上同样的功能,使用Instrospector类完成
BeanInfo beanInfo = Introspector.getBeanInfo(Student.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal1 = null;
for(PropertyDescriptor p1 : pds){
if(p1.getName().equals(property)){
Method method = p1.getReadMethod();
retVal1 = method.invoke(student, null);
break;
}
}
System.out.println(retVal1);
}
}
结果: 22
使用JDK可以完成对JavaBean属性的操作。Apache组织提高了开源项目BeanUtils来方便地操作JavaBean。
二、BeanUtils的使用
2.1 属性的取得和设置
方法 | 说明 |
public static String getProperty(Object bean,String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException | 返回JavaBean的属性值 |
publicstatic void setProperty(Objectbean, String name, Object value) throws IllegalAccessException, InvocationTargetException | 为JavaBen某个属性设置值 |
使用BeanUtils工具类可以很方便地获取JavaBean的属性值和设置属性值。首先来学习以上两个方法:
从以上的方法一中可以看出,使用BeanUtils获取特定属性的的值返回值都是String,这一点在在开发中是非常便利的,比如我们需要获取一个类型为Date的属性的值,通常需要进行类型转换成String,在进行其他操作,但是BeanUtils就可以帮你完成。从方法二中可以看出,第三个参数为Object object,也就是说我们为某个特定属性赋值可以用Object类型传入,BeanUtils为你处理类型转换。
范例:使用BeanUtils操作JavaBean
package com.wisdragon.introspector;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
/**
* 描述: 使用BeanUtils操作JavaBean
* 更新记录:
*/
public class BeanUtilsDemo1 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Student stu = new Student("lee", 22);
//获取属性值
String retVal = BeanUtils.getProperty(stu, "age");
System.out.println(retVal);
//设置属性值
BeanUtils.setProperty(stu, "age", "20"); //BeanUtils做了类型转化,很方便
//BeanUtils.setProperty(stu, "age", 20);
System.out.println(stu.getAge());
}
}
从上面的例子中,我们可以看到,很方便的取得了JavaBean的属性和设置属性,同时返回的值为String,设置值时,age属性的类型为int,可以用字符串传入。
2.2 属性链操作
在开发中对象中包括属性,而此属性同时也是一个对象是常见的事,而这样的属性设置在BeanUtils中很好的实现了这一操作。比如:java.util.Date中有一个setTime()方法,在本文前面的JavaBean例子中已有Date类型的对象了,下面就以这个方法为例。范例:操作属性链
package com.wisdragon.introspector;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
/**
* 描述: 使用BeanUtils操作JavaBean
* 更新记录:
*/
public class BeanUtilsDemo1 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Student stu = new Student("lee", 22);
//支持属性链操作
//java.util.Date 中有一个setTime()方法
BeanUtils.setProperty(stu, "birthday.time", "19920721");
System.out.println(BeanUtils.getProperty(stu, "birthday.time")); //如果不为birthday初始化为一个值,则取得null
}
}
结果: 19920721
从上面的例子中可以看出使用属性.属性代替方法中的属性参数即可。
2.3 其他API
在BeanUtils中还有写API也是常用的,比如在开发中,我们需要将JavaBean转换成一个Map结构,同样也可以反过来操作,BeanUtils提供了API来实现这样的需求。见以下的方法:
方法 | 说明 |
public static Map<String,String> describe(Object bean) throws IllegalAccessException,InvocationTargetException, NoSuchMethodException | 将JavaBean中的属性-值封装成Map结构 |
public static void populate(Object bean, Map<String,? extendsObject> properties) throws IllegalAccessException, InvocationTargetException | 将Map结构中的键值对填充到JavaBean中 |
范例:JavaBean与Map之间的转换
package com.wisdragon.introspector;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
public class BeanUtilsDemo1 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Student stu = new Student("lee", 22);
/*
* describe(Object bean) 返回值:Map<String,String>
* 将JavaBean转换为Map
*/
Map<String, String> map = BeanUtils.describe(stu);
System.out.println(map.get("name"));
System.out.println(map.get("age"));
System.out.println("----------------------------------------------");
/*
* populate(Object bean, Map<String,? extends Object> properties)
* Populate(构建) the JavaBeans properties of the specified bean, based on the specified name/value pairs.
*/
Map<String, String> beanMap = new HashMap<String, String>();
beanMap.put("name", "huangyuze");
BeanUtils.populate(stu, beanMap);
System.out.println(stu);
System.out.println("----------------------------------------------");
}
}
在使用Map结构填充JavaBean时,其Map结构需要符合一定的要求,其键的名称需要与JavaBean的属性名称对应。
2.4 PropertyUtils的使用
我们还可以使用PropertyUtils来完成JavaBean属性的设置与获取,首先来学习这个类的结构:
|
此类也在beanutils包中,只是该类有以下特点:
-| 获取属性值的类型为该属性原始的类型
-| 设置属性值时的值类型只能是该属性原始的类型
范例:使用PropertyUtils类完成JavaBean属性的操作
package com.wisdragon.introspector;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.PropertyUtils;
/**
* 描述: 使用BeanUtils操作JavaBean
* 更新记录:
*/
public class BeanUtilsDemo1 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Student stu = new Student("lee", 22);
/*
* PropertyUtils类的使用
* get属性返回的结果为该属性本来的类型,set属性时只接收该属性本来的类型
*/
Object o = PropertyUtils.getProperty(stu, "age");
System.out.println(o instanceof Integer); //true
// PropertyUtils.setProperty(stu, "age", "22"); //参数类型不匹配
PropertyUtils.setProperty(stu, "age", 18); //参数类型不匹配
System.out.println(stu);
}
}
三、 总结
1、JavaBean是一种特殊的类,其属性的设置和获取方法都符合一定的规则。
2、可以使用JDK提供的内省API 来操作JavaBean的属性。
3、可以使用BeanUtils工具包提供的类来方便的操作JavaBean。