一:内省的概念
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 @Test 2 // 获取所有的属性 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
class
name
salary
其中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
name
salary
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 @Test 2 // 使用beanutils设置属性 3 public void test01() throws Exception { 4 Person p = new Person(); 5 BeanUtils.setProperty(p, "age", 27); // 设置age为27 6 System.out.println(p.getAge()); 7 }
2:beanUtils内部有类型自动转换的机制,String类型可以转换为8种基本数据类型,如下:
1 @Test 2 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 @Override 10 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 Map<String, Object> map = new HashMap<String, Object>(); 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 }
以上代码均已经验证!