内省(introspector):
beanutils内省框架(依赖commons-logging):apache
www.apache.org
学内省的原因: 开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操 作过于麻烦,所以SUN公司开发了一套API,专门用于操作java对象的属性;
通过内省技术访问(java.beans包提供了内省的API)JavaBean的两种方式:
方式1: 通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
方式2: 通过PropertyDescriptor类操作Bean的属性。
注: 属性指的是设置setter和读取getter字段的方法
属性名称是: getName()的属性名称是 name
属性的个数: 以get***()的个数来定 注意: 父类Object中还有一个getClass()的属性
内省-beanutil工具包:
Beanutils是Apache开发的一套快速操作JavaBean getter/setter方法的API,目前比较流行;
准备包: commons-beanutils-1.8.3.jar(zip源码包) 和 commons-logging-1.1.1.jar(zip源码包)
参考: BeanUtils手册.html
语法:
设置属性: BeanUtils.setProperty(Object bean,String propertyName,String propertyValue);
获取属性: BeanUtils.getProperty(Object bean,String PropertyName);
应用:
BeanUtils将Map属性自动放到Bean中;
前提: Map中的key必须要与Bean的属性一致
******************************************************************************************************************************
例1: 内省的基本原理
public class Student {
private String name = "谢霆锋";
private int age = 20;
private Date 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
public class Demo {
// 内省操作的是类中的属性(getter和setter方法)
@Test
public void test1() throws Exception{
// 将Student类中的属性信息封装到BeanInfo的一个对象中
BeanInfo bi = Introspector.getBeanInfo(Student.class);
// 得到类中的所有属性描述器PropertyDescriptor
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
// 输出类/属性描述器中属性的个数,并遍历
System.out.println(pds.length);
for(PropertyDescriptor pd : pds){
System.out.println(pd.getName());
}
}
@Test
public void test2() throws Exception{
// 得到Student类中的name属性描述器 参数:属性名称和该属性所在类的字节码文件
PropertyDescriptor pd = new PropertyDescriptor("name",Student.class);
// 得到getName()方法属性(读方法)
Method m1 = pd.getReadMethod();
// 调用读方法属性并输出该字段的值
Student s = new Student();
String value = (String) m1.invoke(s, null);
System.out.println(value);
// 得到setName()方法属性(写方法),改变name字段的值
Method m2 = pd.getWriteMethod();
// 调用写方法并改变name字段的值
m2.invoke(s, "陈冠希");
System.out.println(s.getName());
}
// 利用BeanUtils框架操作属性,实现原理类似test2,是对上述3个方法的封装
@Test
public void test3() throws Exception{
Student s = new Student();
// 获取name字段的值 : 第一个参数为 对象, 第二个参数为 字段名称
String str = BeanUtils.getProperty(s, "name");
System.out.println(str);
// 设置name字段的值: 参数为: 对象, 字段名称, 设置的新值
BeanUtils.setProperty(s, "name", "新谢霆锋");
System.out.println(s.getName());
}
// BeanUtils可以进行类型的自动转换,但仅限基本类型:
// 如 :int->String(√);但 Date->String(×);
@Test
public void test4() throws Exception{
Student s = new Student();
String str = BeanUtils.getProperty(s, "age");
System.out.println(str);
// BeanUtils.setProperty(s, "age", 30);
BeanUtils.setProperty(s, "age", "30");
System.out.println(s.getAge());
}
/* 注: 该方法会报错,无法实现非基本类型的自动转换
@Test
public void test5_1() throws Exception{
Student s = new Student();
String str = BeanUtils.getProperty(s, "birthday");
System.out.println(str);
BeanUtils.setProperty(s, "birthday", "1994-02-25");
System.out.println(s.getBirthday());
}
*/
// 非基本类型的属性的设置:对非基本数据类型的转换 如: String<--->其他类型如 Date
@Test
public void test5_2() throws Exception{
Student s = new Student();
// 给BeanUtils注册类型转换器: 自定义转换器
ConvertUtils.register(new Converter() {
// 参数 第一个type为: 目标类型, 第二个value为: 当前传入的值
public Object convert(Class type, Object value) {
//// 根据目标类型判断类型转换方式
//if(type.equals(Date.class)){
// // 字符串-->Date
//}else{
//// Date-->字符串
//}
// 根据当前传入的值判断类型转换方式
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
if(value instanceof String){
// 字符串-->Date
String v = (String)value;
try {
Date d = df.parse(v);
return d;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}else{
// Date-->字符串
Date d = (Date) value;
return df.format(d);
}
}}, Date.class);
BeanUtils.setProperty(s, "birthday", "1994-02-26");
System.out.println(s.getBirthday());
}
@Test // 使用已经封装好的BeanUtils中的日期转换器,日期转换器原理参考test5
public void test5_3() throws Exception{
Student s = new Student();
// 给BeanUtils注册类型转换器: 自定义转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.setProperty(s, "birthday", "1994-02-26");
System.out.println(s.getBirthday());
}
}
********************************************************************************************************************
例2: 利用BeanUtils将Map中的数据封装到Bean中
public class Person {
private String name;
private int age;
private Date 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Person [age=" + age + ", birthday=" + birthday + ", name="
+ name + "]";
}
}
// 利用BeanUtils封装数据
public class Demo {
@Test
public void test() throws Exception{
Map map = new HashMap(); // map中的key与属性一致
map.put("name", "小王");
map.put("age", "30");
map.put("birthday", "1994-02-22");
Person p = new Person();
System.out.println("封装数据前:" + p);
// 通过转换器将非基本类型数据转换成字符串,然后再将Map中的属性统一封装到Bean中
ConvertUtils.register(new DateLocaleConverter(),Date.class);
BeanUtils.populate(p, map);
System.out.println("封装数据后:" + p);
}
}
beanutils内省框架(依赖commons-logging):apache
www.apache.org
学内省的原因: 开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操 作过于麻烦,所以SUN公司开发了一套API,专门用于操作java对象的属性;
通过内省技术访问(java.beans包提供了内省的API)JavaBean的两种方式:
方式1: 通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
方式2: 通过PropertyDescriptor类操作Bean的属性。
注: 属性指的是设置setter和读取getter字段的方法
属性名称是: getName()的属性名称是 name
属性的个数: 以get***()的个数来定 注意: 父类Object中还有一个getClass()的属性
内省-beanutil工具包:
Beanutils是Apache开发的一套快速操作JavaBean getter/setter方法的API,目前比较流行;
准备包: commons-beanutils-1.8.3.jar(zip源码包) 和 commons-logging-1.1.1.jar(zip源码包)
参考: BeanUtils手册.html
语法:
设置属性: BeanUtils.setProperty(Object bean,String propertyName,String propertyValue);
获取属性: BeanUtils.getProperty(Object bean,String PropertyName);
应用:
BeanUtils将Map属性自动放到Bean中;
前提: Map中的key必须要与Bean的属性一致
******************************************************************************************************************************
例1: 内省的基本原理
public class Student {
private String name = "谢霆锋";
private int age = 20;
private Date 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
public class Demo {
// 内省操作的是类中的属性(getter和setter方法)
@Test
public void test1() throws Exception{
// 将Student类中的属性信息封装到BeanInfo的一个对象中
BeanInfo bi = Introspector.getBeanInfo(Student.class);
// 得到类中的所有属性描述器PropertyDescriptor
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
// 输出类/属性描述器中属性的个数,并遍历
System.out.println(pds.length);
for(PropertyDescriptor pd : pds){
System.out.println(pd.getName());
}
}
@Test
public void test2() throws Exception{
// 得到Student类中的name属性描述器 参数:属性名称和该属性所在类的字节码文件
PropertyDescriptor pd = new PropertyDescriptor("name",Student.class);
// 得到getName()方法属性(读方法)
Method m1 = pd.getReadMethod();
// 调用读方法属性并输出该字段的值
Student s = new Student();
String value = (String) m1.invoke(s, null);
System.out.println(value);
// 得到setName()方法属性(写方法),改变name字段的值
Method m2 = pd.getWriteMethod();
// 调用写方法并改变name字段的值
m2.invoke(s, "陈冠希");
System.out.println(s.getName());
}
// 利用BeanUtils框架操作属性,实现原理类似test2,是对上述3个方法的封装
@Test
public void test3() throws Exception{
Student s = new Student();
// 获取name字段的值 : 第一个参数为 对象, 第二个参数为 字段名称
String str = BeanUtils.getProperty(s, "name");
System.out.println(str);
// 设置name字段的值: 参数为: 对象, 字段名称, 设置的新值
BeanUtils.setProperty(s, "name", "新谢霆锋");
System.out.println(s.getName());
}
// BeanUtils可以进行类型的自动转换,但仅限基本类型:
// 如 :int->String(√);但 Date->String(×);
@Test
public void test4() throws Exception{
Student s = new Student();
String str = BeanUtils.getProperty(s, "age");
System.out.println(str);
// BeanUtils.setProperty(s, "age", 30);
BeanUtils.setProperty(s, "age", "30");
System.out.println(s.getAge());
}
/* 注: 该方法会报错,无法实现非基本类型的自动转换
@Test
public void test5_1() throws Exception{
Student s = new Student();
String str = BeanUtils.getProperty(s, "birthday");
System.out.println(str);
BeanUtils.setProperty(s, "birthday", "1994-02-25");
System.out.println(s.getBirthday());
}
*/
// 非基本类型的属性的设置:对非基本数据类型的转换 如: String<--->其他类型如 Date
@Test
public void test5_2() throws Exception{
Student s = new Student();
// 给BeanUtils注册类型转换器: 自定义转换器
ConvertUtils.register(new Converter() {
// 参数 第一个type为: 目标类型, 第二个value为: 当前传入的值
public Object convert(Class type, Object value) {
//// 根据目标类型判断类型转换方式
//if(type.equals(Date.class)){
// // 字符串-->Date
//}else{
//// Date-->字符串
//}
// 根据当前传入的值判断类型转换方式
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
if(value instanceof String){
// 字符串-->Date
String v = (String)value;
try {
Date d = df.parse(v);
return d;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}else{
// Date-->字符串
Date d = (Date) value;
return df.format(d);
}
}}, Date.class);
BeanUtils.setProperty(s, "birthday", "1994-02-26");
System.out.println(s.getBirthday());
}
@Test // 使用已经封装好的BeanUtils中的日期转换器,日期转换器原理参考test5
public void test5_3() throws Exception{
Student s = new Student();
// 给BeanUtils注册类型转换器: 自定义转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.setProperty(s, "birthday", "1994-02-26");
System.out.println(s.getBirthday());
}
}
********************************************************************************************************************
例2: 利用BeanUtils将Map中的数据封装到Bean中
public class Person {
private String name;
private int age;
private Date 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Person [age=" + age + ", birthday=" + birthday + ", name="
+ name + "]";
}
}
// 利用BeanUtils封装数据
public class Demo {
@Test
public void test() throws Exception{
Map map = new HashMap(); // map中的key与属性一致
map.put("name", "小王");
map.put("age", "30");
map.put("birthday", "1994-02-22");
Person p = new Person();
System.out.println("封装数据前:" + p);
// 通过转换器将非基本类型数据转换成字符串,然后再将Map中的属性统一封装到Bean中
ConvertUtils.register(new DateLocaleConverter(),Date.class);
BeanUtils.populate(p, map);
System.out.println("封装数据后:" + p);
}
}