内省
一、内省概述
内省:就是操作javaBean的,而JavaBean的属性是根据setter和getter方法来确定的。如果自己通过getXX方法来访问私有的XX,有一定的难度。而使用内省可以很方便的操作JavaBean的私有字段。
那什么是JavaBean呢?
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
下面是一个JavaBean的例子:
public class ReflectPiont {
//私有的字段
private int x;
private int y;
//构造函数
public ReflectPiont(int x, int y) {
super();
this.x = x;
this.y = y;
}
//setter和getter方法
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
//重写hashCode方法
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
//重写equals方法
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPiont other = (ReflectPiont) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
二、内省的操作方式
内省有三种操作方式,下面就逐一看一下:
1.使用PropertyDescriptor来实现内省
PropertyDescriptor是java.bean包下的一个子类,它描述JavaBean通过一对存储器方法导出的一个属性。
可以通过getReadMethod和getWriteMethod来操作JavaBean的私有字段。
下面看一下例子:
//使用PropertyDescriptor来实现内省
public class IntroSpectorDemo {
public static void main(String[] args) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ReflictPiont rp = new ReflictPiont(5,3);//ReflictPiont为一个JavaBean
String propertyName = "x";
//传入两个参数,一个是要操作的字段,另一个是对象字节码
PropertyDescriptor pd = new PropertyDescriptor(propertyName, rp.getClass());
//获得应该用于读取属性值的方法。
getProperty(rp, pd);
Object value = 7;
//设置属性的方法
setProperty(rp, pd, value);
}
private static void setProperty(ReflictPiont rp, PropertyDescriptor pd,
Object value) throws IllegalAccessException,
InvocationTargetException {
Method methodsetX = pd.getWriteMethod();//获取写方法
methodsetX.invoke(rp, value);//执行方法
System.out.println(rp.getX());//可以得到修改后的值
}
//获得应该用于读取属性值的方法。
private static void getProperty(ReflictPiont rp, PropertyDescriptor pd)
throws IllegalAccessException, InvocationTargetException {
Method methodgetX = pd.getReadMethod();//获取读方法
Object retVal = methodgetX.invoke(rp);//执行方法
System.out.println(retVal);
}
}
2.使用IntroSpector和BeanInfo来实现内省
IntroSpector是java.bean包下的子类,Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。
BeanInfo是java.bean包下的接口,希望提供有关其 bean 的显式信息的 bean 实现者可以提供某个 BeanInfo 类,该类实现此 BeanInfo 接口并提供有关其 bean 的方法、属性、事件等显式信息。
Introspector的一个静态方法getBeanInfo可以获得BeanInfo的引用。再通过BeanInfo引用的方法getPropertyDescriptors(),可以得到PropertyDescriptor的数组对象,通过遍历PropertyDescriptor数组对JavaBean进行获取或修改操作。
如下:
//使用IntroSpector
public class IntroSpectorDemo2 {
public static void main(String[] args) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, Exception {
ReflictPiont rp = new ReflictPiont(5,3);
String propertyName = "x";
//getProperty(rp, propertyName);
int x = 42;
setProperty(rp, propertyName, x);
}
private static void getProperty(ReflictPiont rp, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
//返回BeanInfo对象
BeanInfo beanInfo = Introspector.getBeanInfo(rp.getClass());
//调用getPropertyDescriptors方法,返回数组
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
//遍历,并得到想要得到的属性
for(PropertyDescriptor pd :pds){
if(pd.getName().equals(propertyName)){
//判断满足条件后,获得get方法
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(rp);//执行方法
System.out.println(retVal);
break;
}
}
}
private static void setProperty(ReflictPiont rp, String propertyName, int x)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(rp.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd : pds){
//判断满足条件后,获得set方法
Method setX = pd.getWriteMethod();
if(pd.getName().equals(propertyName)){
setX.invoke(rp, x); //执行方法
System.out.println(rp.getX());
break;
}
}
}
}
3.使用第三方JAR包BeanUtils来实现内省
BeanUtils是Apache的工具包,通过导入这个jar包,能够实现对JavBean进行内省操作。
通过BeanUtils类的getProperty和setProperty方法可以直接操作JavaBean,简洁方便。
如:
public class IntroSpectorDemo3 {
public static void main(String[] args) throws Exception {
ReflectPiont p = (ReflectPiont) Class.forName("com.itheima.ReflectPiont").getConstructor(int.class,int.class).newInstance(12,5);
System.out.println(BeanUtils.getProperty(p, "x"));//直接通过getProperty方法获得字段
}
}
可以看见这种方式最为方便。