内省机制(内省机制的学习需要先了解JavaBean规范)
通过内省类(Introspector)可以生成对应字节码对象的BeanInfo类(包含了三大成员 -----> 事件、方法、属性)。一般对BeanInfo类中的属性(Property)进行操作。
BeanInfo类中的属性(Property)是通过符合javabean规范的get/set方法推导出来的。(只要方法名的前缀是get或set,后面的字符串首字母小写后就是一个属性的名字)
规范的get方法-读方法:public修饰,无参数,有返回,get开头.
规范的set方法-写方法:public修饰,有参数,无返回,set开头.
注意:
- 只要是标准的get/set方法,就存在属性。(不一定是成员变量)
- Javabean规范中,返回值是boolean的,读方法不是get开头,是is开头
最后附赠一个内省机制操作Bean属性的工具类和测试代码
(验证测试代码时:需要lombok的jar包;或者按照JavaBean规范重写测试代码中的Person类)
package cn.web03;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @name: MyBeanUtils
* @Description: JavaBean属性操作工具类
* @Author: leaf
* @CreateDate: 2019年12月5日
* @Version: V1.0
*/
public class MyBeanUtils {
private static final MyBeanUtils myBeanUtils=new MyBeanUtils();
private MyBeanUtils() {}
public static MyBeanUtils getInstance() {
return myBeanUtils;
}
/**
* @Name: setPropertyValue
* @Description: 根据指定的bean实例对象,给指定属性名称的属性设置对应属性值
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月5日
* @Parameters: String propertyName 属性名称
* @Parameters: Object propertyValue 属性值
* @Parameters: Object bean bean实例对象
* @Return: void
*/
public void setPropertyValue(String propertyName,Object propertyValue,Object bean) {
try {
PropertyDescriptor pd = new PropertyDescriptor(propertyName,bean.getClass());
if(!pd.getPropertyType().equals(propertyValue.getClass())){
throw new Exception("属性类型不匹配!该属性的类型是"+pd.getPropertyType()+",你输入的类型是"+propertyValue.getClass());
}
Method m = pd.getWriteMethod();
if(m!=null) {
m.invoke(bean, propertyValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Name: getPropertyValue
* @Description: 根据指定的bean对象的属性名称,获取属性值
* @Author: leaf
* @Version: V1.0
* @CreateDate: 2019年12月5日
* @Parameters: propertyName 属性名称
* @Parameters: bean bean实例对象
* @Return: Object 返回getter方法的返回值,即属性值
*/
public Object getPropertyValue(String propertyName,Object bean) {
Object propertyValue = null;
try {
PropertyDescriptor pd = new PropertyDescriptor(propertyName,bean.getClass());
Method m = pd.getReadMethod();
if(m!=null) {
propertyValue = m.invoke(bean);
}
} catch (Exception e) {
e.printStackTrace();
}
return propertyValue;
}
/**
* @Name: bean2Map
* @Description: 把bean的实例对象转换成Map
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月6日
* @Parameters: Object bean bean实例对象
* @Return: Map<String,Object>
*/
public Map<String,Object> bean2Map(Object bean){
Map<String,Object> map = new HashMap<>();
try {
BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String key = pd.getName();
Method m = pd.getReadMethod();
if(m!=null) {
Object obj = m.invoke(bean);
map.put(key, obj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
/**
* @Name: map2Bean
* @Description: 把Map中的数据传给Bean实例对象
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月5日
* @Parameters: Map<String,Object> map 存储数据的map集合
* @Parameters: Object bean Bean的实例对象
* @Return: void
*/
public void map2Bean(Map<String,Object> map,Object bean) {
try {
BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String key = pd.getName();
Method m = pd.getWriteMethod();
if(m!=null && map.containsKey(key)) {
m.invoke(bean, map.get(key));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试代码
package cn.web03;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
* @name: TestMyBeanUtils
* @Description: 测试MyBeanUtils类的测试类
* @Author: leaf
* @CreateDate: 2019年12月6日
* @Version: V1.0
*/
public class TestMyBeanUtils {
@Getter //成员变量的getter方法
@Setter //成员变量的setter方法
@NoArgsConstructor //无参构造器
@AllArgsConstructor //全参构造器
@ToString //toString
@EqualsAndHashCode //equals和hashCode
private class Person{
private String name;
private Integer age;
}
Person p = new Person("黄华",18);
private MyBeanUtils utils = MyBeanUtils.getInstance();
/**
* @Name: testSetPropertyValue
* @Description: 测试setPropertyValue方法。根据指定的bean实例对象,给指定属性名称的属性设置对应属性值
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月6日
* @Parameters: null
* @Return: void
*/
@Test
public void testSetPropertyValue(){
utils.setPropertyValue("name", "黄辉", p);
utils.setPropertyValue("age", 20, p);
System.out.println(p);
System.out.println("-------------------------");
}
/**
* @Name: testGetPropertyValue
* @Description: 测试getPropertyValue方法。根据指定的bean对象的属性名称,获取属性值
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月6日
* @Parameters: null
* @Return: void
*/
@Test
public void testGetPropertyValue() {
Object name = utils.getPropertyValue("name", p);
Object age = utils.getPropertyValue("age", p);
System.out.println(name+","+age);
System.out.println("-------------------------");
}
/**
* @Name: testBean2Map
* @Description: 测试map2Bean方法和bean2Map方法。把bean的实例对象转换成Map,把Map中的数据传给Bean实例对象
* @Author: leaf
* @Version: 1.0
* @CreateDate: 2019年12月6日
* @Parameters: null
* @Return: void
*/
@Test
public void testBean2Map() throws Exception {
Map<String,Object> map = utils.bean2Map(p);
Set<String> set = map.keySet();
for (String str : set) {
System.out.println(str+":"+map.get(str));
}
System.out.println("-------------------------");
map.put("name", "黄迪");
map.put("age", 28);
utils.map2Bean(map, p);
System.out.println(p);
}
}