在实际编程中,我们常常需要一些用来包装值对象的类,例如Student、Employee、Order,这些类中往往没有业务方法,只是为了把需要处理的实体对象进行封装,有这样的特征:
属性都是私有的;
有无参的public构造方法;
对私有属性根据需要提供 公有的getXxx方法以及setXxx方法;例如属性名称为name,则有getName方法返回属性name值,setName方法设置name值;注意方法的名称通常是get或set加上属性名称,并把属性名称的首字母大写;这些方法称为getters/setters;getters必须有返回值没有方法参数;setter值没有返回值,有方法参数;
符合这些特征的类,被称为JavaBean;
内省(Inspector)机制就是基于反射的基础,Java语言对Bean类属性、事件的一种缺省处理方法。
注意:只要类中有getXXX方法,或者setXXX方法,或者同时有getXXX及setXXX方法,其中getXXX方法没有方法参数,有返回值;setXXX方法没有返回值,有一个方法参数;那么内省机制就认为XXX为一个属性;
内省机制检索属性时,是根据getter和setter方法确认属性名字,而不是根据类里声明的属性名决定;
package com.yh.reflex;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
/**
* --内省
*
*/
public class Demo03 {
public static void main(String[] args)throws Exception {
String className = "com.yh.reflex.Student";
Class<?> cls = Class.forName(className);
System.out.println(cls);
BeanInfo studentInfo = Introspector.getBeanInfo(cls);
PropertyDescriptor[] propertys = studentInfo.getPropertyDescriptors();//属性;get,set
for(PropertyDescriptor p : propertys) {
System.out.println(p.getName());
System.out.println("\t"+p.getPropertyType());//属性类型
System.out.println("\t"+p.getReadMethod());//get方法
System.out.println("\t"+p.getWriteMethod());//set方法
}
}
}
内省的用处:
比如在JDBC中,可通过内省的方式对在对象之间进行属性的复制
package com.yh.util;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 用来复制属性值;相当于cn.hutool.core.bean.BeanUtil.copyProperties
*
*/
public class BeanUtil {
private BeanUtil() {}
/**
*
* @param sourceBean 被复制的对象;已知
* @param targetBean 复制到的对象;目标
* @param ignoreProperties 哪些属性不被复制
*/
public static void copy(Object sourceBean,Object targetBean,String...ignoreProperties) {
Set<String> ignorePropertiesSet = new HashSet<>();
if(ignoreProperties!=null){
java.util.Collections.addAll(ignorePropertiesSet, ignoreProperties);
}
Class<?> sourceClass = sourceBean.getClass();
Class<?> targetClass = targetBean.getClass();
try {
BeanInfo sourceInfo = Introspector.getBeanInfo(sourceClass);
PropertyDescriptor[] propertys = sourceInfo.getPropertyDescriptors();
Map<String, PropertyDescriptor> map = new HashMap<String, PropertyDescriptor>();
for(PropertyDescriptor p : propertys) {
map.put(p.getName(), p);
}
BeanInfo targetInfo = Introspector.getBeanInfo(targetClass);
propertys = targetInfo.getPropertyDescriptors();
for(PropertyDescriptor p : propertys) {
if(p.getWriteMethod()==null) {//如果目标bean的属性没有setter,跳过,进入下一个属性
continue;
}
if(ignorePropertiesSet.contains(p.getName())) {//如果目标bean的属性在忽略的属性中,跳过
continue;
}
PropertyDescriptor sourceProperty = map.get(p.getName());
if(sourceProperty == null || sourceProperty.getReadMethod() == null) {//如果原对象没有对应的getter方法,跳过
continue;
}
//以上条件都成立后,将原对象要复制的属性的值进行获取
Object obj = sourceProperty.getReadMethod().invoke(sourceBean);
//将该值复制给目标对象
if(obj != null) {
p.getWriteMethod().invoke(targetBean, obj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}