一:内省的概念
1:内省是反射的一种特例,由于在反射中频繁的操作javabean,所以为了方便反射
javabean,sun公司开发出一套API提高效率。
2:javaBean,就是用来封装客户端请求数据,有字段、get、set方法的对象,javaBean对象的属性有getXXX方法
决定。
二:内省访问JavaBean
1:定义javaBean
1 public class Person { 2 private String name; 3 private int age; 4 5 public String getName() { 6 return name; 7 } 8 9 public void setName(String name) {10 this.name = name;11 }12 13 public int getAge() {14 return age;15 }16 17 public void setAge(int age) {18 this.age = age;19 }20 21 public double getSalary() {22 return 12000.0;23 }24 }
2:访问javaBean对象
a:获取所有的属性
1 @Test2 // 获取所有的属性3 public void test1() throws Exception {4 BeanInfo bi = Introspector.getBeanInfo(Person.class);5 PropertyDescriptor[] pds = bi.getPropertyDescriptors();6 for (PropertyDescriptor pd : pds) {7 System.out.println(pd.getName());8 }9 }
运行结果:
age
classnamesalary其中age ,name是定义的成员变量,salary是getSlary()方法定义的,class是因为Person继承了Object类,
所以也继承了Object的方法getClass();
要想得到自己定义的类,可以使用getBeanInfof(Person.class,Object.class)方法,如下:
1 @Test 2 // 获取所有的属性 3 public void test1() throws Exception { 4 // BeanInfo bi = Introspector.getBeanInfo(Person.class); 5 BeanInfo bi = Introspector.getBeanInfo(Person.class, Object.class); 6 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); 7 for (PropertyDescriptor pd : pds) { 8 System.out.println(pd.getName()); 9 }10 }
运行结果:
age
namesalary
b:操作属性
1 @Test 2 // 操作属性 3 public void test2() throws Exception { 4 Person p = new Person(); 5 PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); 6 // 获取getxxx()方法 7 Method m = pd.getWriteMethod(); 8 m.invoke(p, 27); 9 // 获取setxxx()方法10 m = pd.getReadMethod();11 System.out.println(m.invoke(p, null));12 }
c:获取当前属性的类型
1 // 获取当前属性的类型2 public void test3() throws Exception {3 PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);4 System.out.println(pd.getPropertyType());5 }
运行结果:
int
三:BeanUtils工具类的使用
beanUtils工具是apache基金会为了方便操作javaBean类,开发的一套API,在实际的开发中使用多于内省。
1:使用beanUtils设置属性的值
1 @Test2 // 使用beanutils设置属性3 public void test01() throws Exception {4 Person p = new Person();5 BeanUtils.setProperty(p, "age", 27); // 设置age为276 System.out.println(p.getAge());7 }
2:beanUtils内部有类型自动转换的机制,String类型可以转换为8种基本数据类型,如下:
1 @Test2 public void test02() throws Exception {3 Person p = new Person();4 String name = "Jack";5 String age = "27";6 BeanUtils.setProperty(p, "name", name);7 BeanUtils.setProperty(p, "age", age); // 这里String类型转换为int类型8 System.out.println(p.getName() + ":" + p.getAge());9 }
本来Person类中age为int类型,但是String类型的age直接赋给了bean,但是转换仅限于8种基本数据类型。
3:如果是其他的类型,则转换会失败,如下Date类型,String转换是就会报错:
1 @Test 2 public void test03() throws Exception { 3 Person p = new Person(); 4 String name = "Jack"; 5 String age = "27"; 6 String birthday = "2010-10-02"; 7 BeanUtils.setProperty(p, "name", name); 8 BeanUtils.setProperty(p, "age", age); // 这里String类型转换为int类型 9 BeanUtils.setProperty(p, "birthday", birthday); // 这里会报错,因为String类型自动转化仅限于8种基本类型10 System.out.println(p.getName() + ":" + p.getAge() + ":"11 + p.getBirthday());12 }
异常如下:
4:自定义String到Date的转化器
1 @Test 2 public void test04() throws Exception { 3 Person p = new Person(); 4 String name = "Jack"; 5 String age = "27"; 6 String birthday = "2010-10-02"; 7 ConvertUtils.register(new Converter() { 8 9 @Override10 public Object convert(Class arg0, Object value) {11 if (value == null) {12 return null;13 }14 if (!(value instanceof String)) {15 throw new ConversionException("转换异常!");16 }17 String str = (String) value;18 if (str.trim().equals("")) {19 return null;20 }21 // 排除以上情况,开始转换22 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");23 try {24 return sdf.parse(str);25 } catch (ParseException e) {26 throw new RuntimeException(e);27 }28 }29 30 }, Date.class); // 将转换器里定义转换方法31 BeanUtils.setProperty(p, "name", name);32 BeanUtils.setProperty(p, "age", age); // 这里String类型转换为int类型33 BeanUtils.setProperty(p, "birthday", birthday); // 这里会报错,因为String类型自动转化仅限于8种基本类型34 System.out.println(p.getName() + ":" + p.getAge() + ":"35 + p.getBirthday());36 }
转换成功!
5:使用BeanUtils定义的转化器
1 @Test 2 public void test05() throws Exception { 3 Person p = new Person(); 4 String name = "Jack"; 5 String age = "27"; 6 String birthday = "2010-10-02"; 7 ConvertUtils.register(new DateLocaleConverter(), Date.class); // 将转换器里定义转换方法 8 BeanUtils.setProperty(p, "name", name); 9 BeanUtils.setProperty(p, "age", age); // 这里String类型转换为int类型10 BeanUtils.setProperty(p, "birthday", birthday); // 这里会报错,因为String类型自动转化仅限于8种基本类型11 System.out.println(p.getName() + ":" + p.getAge() + ":"12 + p.getBirthday());13 }
但是这里有几个问题:
a:导包错误,导入java.util.Date,而不是java.sql.Date,否则报错,如下:
b:导入的commons-beanUtils.jar版本不对,建议commons-beanUtils-1.9.2.jar或者commons-beanUtils-1.9.2.jar都可以,
否则报错如下:
c:但是使用自定义的转换器有缺点,就是当日期字符串为空时,它不能判断,仍然后进行转换,异常如下:
但是自定义的转换器是没有这个问题的。
6:将map里存储的key-value封装到bean里面
1 @Test 2 public void test06() throws Exception { 3 Person p = new Person(); 4 Mapmap = new HashMap (); 5 String name = "Jack"; 6 String age = "27"; 7 String birthday = "2010-10-02"; 8 ConvertUtils.register(new DateLocaleConverter(), Date.class); 9 map.put("name", name);10 map.put("age", age);11 map.put("birthday", birthday);12 BeanUtils.populate(p, map);13 System.out.println(p.getName());14 System.out.println(p.getAge());15 System.out.println(p.getBirthday());16 }
以上代码均已经验证!