为什么要学内省?
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦
所以sun公司开发了一套API,专门用于操作java对象的属性。
什么是Java对象的属性和属性的读写方法?
内省访问JavaBean属性的两种方式:
内省是 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工具包的常用类:
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()+"..."); } }