为什么要学内省?
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦
所以sun公司开发了一套API,专门用于操作java对象的属性。
什么是Java对象的属性和属性的读写方法?
内省访问JavaBean属性的两种方式:
- 通过PropertyDescriptor类操作Bean的属性
- 通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
内省是 Java 语言对 Bean 类属性的一种缺省处理方法。
例如类 A 中有属性 name, 可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这是默认的规则。 Java 中提供了一套 API 来访问某个属性的 getter/setter 方法。
一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法
package net.csdn.high;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Test;
public class StudentDemo {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
StudentDemo sd = new StudentDemo();
sd.test1();
sd.test2();
sd.Test3();
sd.Test4();
}
@Test
//通过内省获取person bean的所有属性
public void test1() throws IntrospectionException{
BeanInfo bi = Introspector.getBeanInfo(Student.class,Object.class);
PropertyDescriptor[] pds=bi.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
String name=pd.getName();
System.out.println(name);
}
System.out.println("--------");
}
//通过内省给person的name属性赋值:张三 setName("张三")
@Test
public void test2() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
Student s = new Student();
BeanInfo bi = Introspector.getBeanInfo(Student.class);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
String name = pd.getName();
if(name.equals("name")){
Method m = pd.getWriteMethod();
m.invoke(s, "张三");
}
}
System.out.println(s.getName());
System.out.println("--------");
}
//通过PropertyDescriptor类操作Bean的属性 name属性赋值:张三 setName("李四")
@Test
public void Test3() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
Student s = new Student();
PropertyDescriptor pd = new PropertyDescriptor("name", s.getClass());
Method m=pd.getWriteMethod();
m.invoke(s,"李四");
System.out.println(s.getName());
System.out.println("--------");
}
@Test
public void Test4() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
Student s = new Student();
s.setName("王五");
PropertyDescriptor pd = new PropertyDescriptor("name",s.getClass());
Method m = pd.getReadMethod();
String str = (String)m.invoke(s, null);
System.out.println(str);
}
}
Sun公司的内省API过于繁琐,所以Apache组织结合很多实际开发中的应用场景开发了一套简单、易用的API操作Bean的属性——BeanUtils
Beanutils工具包的常用类:
- BeanUtils
- PropertyUtils
- ConvertUtils.regsiter(Converter convert, Class clazz)
package net.csdn.high;
import java.util.Date;
public class Student {
private String name;
private int age;
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
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;
}
}
package net.csdn.high;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
public class StudentBeanutilsDemo {
@Test
public void test1() throws IllegalAccessException, InvocationTargetException{
Student s = new Student();
BeanUtils.setProperty(s,"name","张三");
System.out.println(s.getName());
}
}
当有日期类型时候,如果有空格,程序会出错:
package net.csdn.high;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import org.junit.Test;
public class StudentBeanutilsDemo {
@Test
public void test3() throws IllegalAccessException, InvocationTargetException{
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Student s = new Student();
BeanUtils.setProperty(s,"birthday"," ");
//System.out.println(p.getBirthday());
}
}
自定义转换器
package net.csdn.high;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.junit.Test;
public class StudentBeanutilsDemo {
//beanutils工具对基本数据类型可以自动转换类型
@Test
public void test2() throws IllegalAccessException, InvocationTargetException{
//自定义转换器
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 s=(String)value;
if(s.trim().equals("")){
return null;
}
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
Date d=sdf.parse(s);
return d;
} catch (ParseException e) {
// TODO Auto-generated catch block
throw new ConversionException("转换错误");
}
}
}, Date.class);
String name = "张三";
String age = "23";
String birthday = " ";
Student s = new Student();
BeanUtils.setProperty(s,"name",name);
BeanUtils.setProperty(s,"age",age);
BeanUtils.setProperty(s,"birthday",birthday);
System.out.println(s.getName()+"..."+s.getAge()+"...");
}
}