内省(Introspector) 是Java语言对JavaBean类属性、事件的一种缺省处理方法。
JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object/VO)。这些信息储存在类的私有变量中,通过set()、get()来访问类中的属性。
以下是一个标准的JavaBean:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
在Person类中有属name,age属性, 我们可以通setName()、getName()方法来得到其值或者设置新的值。通过 setName/getName来访问 userName属性,这就是默认的规则。 Java JDK中提供了一套 API 用来访问某个属性的 getter/setter 方法,这就是内省。
JDK中内省的相关类库:
PropertyDescriptor类:
PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:
1. getPropertyType(),获得属性的Class对象;
2. getReadMethod(),获得用于读取属性值的方法;getWriteMethod(),获得用于写入属性值的方法;
3. hashCode(),获取对象的哈希值;
4. setReadMethod(Method readMethod),设置用于读取属性值的方法;
5. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。
使用Java内省操作JavaBean,这是没有任何问题的。但是随之而来的就是编码的复杂度,因此很多第三方类库封装了JavaBean的内省操作,典型的工具包有:BeanUtils工具包(下载地址:http://commons.apache.org/beanutils/)
demo测试代码如下:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) throws Exception {
try {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(Person.class).getPropertyDescriptors();
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
System.out.printf("属性名:%s%n", propertyDescriptor.getName());
System.out.printf("属性类型:%s%n", propertyDescriptor.getPropertyType());
System.out.printf("属性读方法:%s%n", propertyDescriptor.getReadMethod());
System.out.printf("属性写方法:%s%n", propertyDescriptor.getWriteMethod());
}
//测试setProperty()、getProperty()两个方法
testProperty();
//测试setPropertyByIntrospector()、getPropertyByIntrospector()两个方法
testByIntrospector();
//测试BeanUtils工具包
testBeanUtils();
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
/**
* 设置bean的某个属性值
* @param obj
* @param propertyName
* @param value
* @throws Exception
*/
private static void setProperty(Object obj,String propertyName,Object value)throws Exception {
// 获取bean的某个属性的描述符 两种方式
PropertyDescriptor pd = new PropertyDescriptor(propertyName,obj.getClass());
// 获得用于写入属性值的方法
Method setMethod = pd.getWriteMethod();
System.out.printf("写入方法的方法名:%s%n", setMethod.getName());
// 写入属性值
setMethod.invoke(obj, value);
}
/**
* 获取bean的某个属性值
* @param obj
* @param propertyName
* @return
* @throws Exception
*/
private static Object getProperty(Object obj,String propertyName) throws Exception {
// 获取Bean的某个属性的描述符 两种方式
PropertyDescriptor pd = new PropertyDescriptor(propertyName,obj.getClass());
// 获得用于读取属性值的方法
Method getMethod = pd.getReadMethod();
System.out.printf("读取方法的方法名:%s%n", getMethod.getName());
// 读取属性值
return getMethod.invoke(obj);
}
/**
* 通过内省设置bean的某个属性值
* @param obj
* @param propertyName
* @param value
* @throws Exception
*/
public static void setPropertyByIntrospector(Object obj, String propertyName, Object value) throws Exception {
// 获取bean信息
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
// 获取bean的所有属性列表
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
// 遍历属性列表,查找指定的属性
if (propertyDescriptors != null && propertyDescriptors.length > 0) {
for (PropertyDescriptor propDesc : propertyDescriptors) {
// 找到则写入属性值
if (propDesc.getName().equals(propertyName)) {
Method methodSetUserName = propDesc.getWriteMethod();
System.out.printf("写入方法的方法名:%s%n", methodSetUserName.getName());
// 写入属性值
methodSetUserName.invoke(obj, value);
break;
}
}
}
}
/**
* 通过内省获取bean的某个属性值
* @param obj
* @param propertyName
* @throws Exception
*/
public static Object getPropertyByIntrospector(Object obj, String propertyName) throws Exception {
// 获取bean信息
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
// 获取bean的所有属性列表
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
if (propertyDescriptors != null && propertyDescriptors.length > 0) {
for (PropertyDescriptor propDesc : propertyDescriptors) {
// 找到则读取属性值
if (propDesc.getName().equals(propertyName)) {
Method methodGetUserName = propDesc.getReadMethod();
System.out.printf("读取方法的方法名:%s%n", methodGetUserName.getName());
// 读取属性值
Object objUserName = methodGetUserName.invoke(obj);
return objUserName;
}
}
}
return null;
}
/**
* 测试setProperty()、getProperty()两个方法
* @throws Exception
*/
public static void testProperty() throws Exception {
System.out.println("------------------------------华丽的分割线------------------------------");
Person person = new Person();
String propertyName = "name";
Object nameValue = getProperty(person,propertyName);
System.out.printf("属性name的值=%s%n", nameValue);
Object name = "张三";
setProperty(person, propertyName, name);
System.out.printf("get()获取属性name的值=%s%n", person.getName());
System.out.printf("getProperty()获取属性name的值=%s%n", getProperty(person, propertyName));
}
/**
* 测试setPropertyByIntrospector()、getPropertyByIntrospector()两个方法
* @throws Exception
*/
public static void testByIntrospector() throws Exception {
System.out.println("------------------------------华丽的分割线------------------------------");
Person personOther = new Person();
String propertyAge = "age";
Object ageValue = getPropertyByIntrospector(personOther,propertyAge);
System.out.printf("属性age的值=%s%n", ageValue);
Object age = 20;
setPropertyByIntrospector(personOther, propertyAge, age);
System.out.printf("get()获取属性age的值=%s%n", personOther.getAge());
System.out.printf("getPropertyByIntrospector()获取属性age的值=%s%n", getPropertyByIntrospector(personOther, propertyAge));
}
/**
* 内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
* 下载地址:http://commons.apache.org/beanutils/
*/
public static void testBeanUtils() {
System.out.println("------------------------------华丽的分割线------------------------------");
Person person = new Person();
try {
BeanUtils.setProperty(person, "name", "王五");
System.out.printf("name:%s%n", BeanUtils.getProperty(person, "name"));
BeanUtils.setProperty(person, "age", 30);
System.out.printf("age:%s%n", BeanUtils.getProperty(person, "age"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}