内省
一、什么是内省(IntroSpector)
内省(IntroSpector)是Java 语言对 Bean 类属性、事件的一种缺省处理方法,内省的出现有利于了对类对象属性的操作,减少了代码的数量。
二、JavaBean
1,概述:
JavaBean也是一个java类,不过是一种特殊的java类,位于java.bean包中。主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,
且方法名符合某种命名规则。其特殊规则就是,这个java类中有以set和get打头的方法。因此JavaBean也是java类,但是java类却不一定是JavaBean。
2,JavaBean的作用
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问
一个简单的JavaBean
class Person{
//私有的属性
private int x;
//因为方法是给外界操作的,所以访问权限必须是公有的。
public void setAge(int age){
this.x = age;
}
public int getAge(){
return x;
}
}
3,JavaBean的属性
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,如果方法名为getId
去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
setId()的属性名--->id
setCPU的属性名--->CPU
getUPs的属性名--->UPs
4,为什么要使用JavaBean
既然JavaBean也可以当做普通的java类来使用,我们使用JavaBena肯有一定的原因和好处。
1) 在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作。
2) JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,有一定难度,用内省这套api操作
JavaBean比用普通类的方式更方便。
三、对JavaBean 的内省操作
1,对JavaBean简单的内省操作
需求,创建一个名为ReflectPoint的JavaBean,其中有x,y两个属性,通过内省的方式设置和获取属性的值
1) ReflectPoint类
package com.itheima.day1;
public class ReflectPoint {
//两个属性x,y
private int x;//修饰符为private
public int y;//修饰符为public
//set和get方法,所以可以当JavaBean使用
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;
}
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
2) IntroSpectorTest类
package com.itheima.day1;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3, 3);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperty(pt1, propertyName, value);
System.out.println(pt1.getX());
}
//设置属性方法
private static void setProperty(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
//创建属性描述符对象,传入属性名称和对象
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());
//反射得到属性的set方法
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1, value);
}
//获取属性方法
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
//反射得到属性的get方法
Method methodGetX = pd.getReadMethod();
//调用get方法
Object retVal = methodGetX.invoke(pt1);
return retVal;
}
}
2,对JavaBean复杂的内省操作
采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当作JavaBean来看,就是调用IntroSpector.getBeanInfo方法, 得到的
BeanInfo对象封装了把这个类当作JavaBean看的结果信息。将上面程序的getProperty方法通过这个方法进行修改,代码如下:
//获取属性方法
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
//得到所有的属性,返回的是一个数组
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
//定义一个变量用于接收获取的属性值
Object retVal = null;
//对属性进行迭代
for(PropertyDescriptor pd : pds){
//判断属性名是否等于传入的属性名,
if(pd.getName().equals(propertyName)){
//得到属性对应的get方法
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
//如果等于传入的属性名则结束循环
break;
}
}
return retVal;
}
3,通过BeanUtils工具包操作JavaBean
BeanUtils是apache提供的开发库,以便于对JavaBean 的操作。
为了使用BeanUtils工具包,我们需要导入common-beanutils.jar,同时因为BeanUtils工具包自身用到了common-logging-1.1.1.jar,所以还需要导入它。
在上面的程序中演示通过BeanUtils工具包设置和获取属性。
首先在ReflectPoint中加入一个Date类型的birthday属性,生产get和set方法:
package com.itheima.day1;
import java.util.Date;
public class ReflectPoint {
//Date类型的属性birthday(Date类中有个setTime方法)
private Date birthday = new Date();
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
private int x;//修饰符为private
public int y;//修饰符为public
//set和get方法,所以可以当JavaBean使用
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;
}
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
在IntroSpectorTest类中通过BeanUtils对Reflect进行操作:
public class IntroSpectorTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3, 3);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperty(pt1, propertyName, value);
/*-----------------通过BeanUtils工具包操作JavaBean----------------------*/
//获取属性的值
System.out.println(BeanUtils.getProperty(pt1, "x"));
//通过BeanUtils工具包设置属性(BeanUtils是通过字符才来操作的)
BeanUtils.setProperty(pt1, "x", "9");
System.out.println(pt1.getX());
//BeanUtils支持属性的级联操作(Date类中有setTime的方法,所以可以将其当JavaBean操作)
//设置birthday对象的time属性
BeanUtils.setProperty(pt1, "birthday.time", "520");
//获取birthday对象的time属性
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
}