1、什么是JavaBean?
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为“设置id”,至于你把它存到哪个变量上,则不用管。如果方法名为getId,中文意思即为“获取id”,至于你从哪个变量上取,也不用管。去掉set或者get前缀,剩余部分就是属性名。
注意:
如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
如果剩余部分的第二个字母是大写的,则把剩余部分保持不变,保持大写。
例如:
setId的属性名是:id
isLast的属性名是:last
setCPU的属性名是:CPU
getUPS的属性名是:UPS
总之,一个类被当作JavaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
2、使用JavaBean的好处:
一个符合JavaBean特点的类可以当作普通类一样进行使用,但是把它当作JavaBean来使用会带来以下一些额外的好处。
①、在Java EE开发中,经常要使用到JavaBean,很多环境都要去使用JavaBean方式进行操作。
②、JDK中提供了针对JavaBean进行操作的一些API,这套API就称为内省。如果自己通过getX方法来访问私有的X,会有一定的难度。而用内省这套API操作JavaBean 比用普通类的方式更方便。
3、对JavaBean的简单内省操作
需求:通过内省的方式对ReflectPoint类的对象中的成员变量进行读写操作。
代码示例:
ReflectPoint.java
package cn.itcast.day1;
public class ReflectPoint {
private int x;
private int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
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;
}
}
InstroSpectorTest.java
package cn.itcast.day1;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[]args) throws Exception{
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
PropertyDescriptor pd1 = newPropertyDescriptor(propertyName, pt1.getClass());
Method methodGetX = pd1.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
System.out.println(retVal); //结果:3
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,7);
System.out.println(pt1.getX()); //结果:7
}
}
Eclipse中方法抽取:
抽取步骤:右键点击需要被抽取的代码,选择Refactor(重构) → ExtractMethod(抽取方法) → 输入抽取之后的方法名 → 点击OK完成。
方法抽取完成之后的代码如下:
IntroSpectorTest.java
package cn.itcast.day1;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception{
ReflectPoint pt1 = new ReflectPoint(3,5);
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,Objectvalue) throws IntrospectionException,IllegalAccessException,InvocationTargetException {
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
}
private static Object getProperty(Object pt1, String propertyName) throws IntrospectionException,IllegalAccessException,InvocationTargetException{
PropertyDescriptor pd1 = newPropertyDescriptor(propertyName, pt1.getClass());
Method methodGetX = pd1.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
return retVal;
}
}
注意:方法抽取完成之后,为了使抽取后的方法具备通用性,一定要将方法中的某些参数的类型改为Object,以便可以接收任何类型的参数。
4、对JavaBean的复杂内省操作
采用遍历BeanInfo类的所有属性的方式来查找和设置某个ReflectPoint类的对象的x的属性。
在程序中把一个类当作JavaBean来看,就是调用InstroSpector.getBeanInfo()方法,得到的BeanInfo对象封装了把这个类当作JavaBean看的结果信息。
代码示例:
IntroSpectorTest.java
package cn.itcast.day1;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
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) throwsIntrospectionException,IllegalAccessException,InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds){
if (pd.getName().equals(propertyName)){
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(pt1,value);
}
}
}
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)){
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
}
}
return retVal;
}
}
5、使用BeanUtils工具包操作JavaBean
要使用BeanUtils工具包,首先要到Apache的官网上去下载BeanUtils工具包(http://commons.apache.org/ ),下载完成之后解压,然后再导入到Eclipse的工程里面去。
选中当前工程,在当前工程下创建一个普通文件夹目录lib,然后将beanutils的jar包拷贝到lib目录中
拷贝过来之后就可以在Eclipse当中看到beanutils的jar包了。
接下来需要将刚刚拷贝过来的jar包添加到Build Path当中,右键点击该jar包,选择Build Path → Add toBuild Path
添加到Build Path之后会在左边列表栏上出现一个小瓶子的图标,表示该jar包已经添加成功了
当使用beanutils工具包中的方法来操作JavaBean的时候,会出现如下报错,原因是beanutils工具包依赖于logging包(此jar包也可以在Apache官网下载),因此也需要下载logging日志包并添加到当前工程当中去,步骤和添加beanutils工具包一样。
添加common-logging包到Eclipse工程当中,添加之后同意也需要添加到Build Path,步骤和添加beanutils到Build Path当中一样。
使用BeanUtils工具包可以很方便的实现对JavaBean对象中成员变量的获取和设置等操作。
代码示例:
IntroSpectorTest.java
package cn.itcast.day1;
import org.apache.commons.beanutils.BeanUtils;
public class IntroSpectorTest {
public static void main(String[]args) throws Exception{
ReflectPoint pt1 = new ReflectPoint(3,5);
System.out.println(BeanUtils.getProperty(pt1,"x"));
//结果:7
BeanUtils.setProperty(pt1,"x", "9");
System.out.println(pt1.getX());
//结果:9
}
}
注意:
①、BeanUtils工具类在对对象的属性进行操作的时候,会自动进行类型转换。
例如:ReflectPoint类中的变量x是int类型,但是设置属性值的时候传入的参数却可以是String类型,这时因为它内部发生了自动类型转换。(示例如上)
②、BeanUtils工具类可以对属性进行级联操作。
例如:Date类中有一个setTime()方法,那么也就相当于Date类型对象有一个名为time属性,BeanUtils工具类就可以对其进行操作。(示例如下)
代码示例:
ReflectPoint.java
package cn.itcast.day1;
import java.util.Date;
public class ReflectPoint {
private Date birthday = newDate();
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday){
this.birthday = birthday;
}
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
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;
}
}
IntroSpectorTest.java
package cn.itcast.day1;
importorg.apache.commons.beanutils.BeanUtils;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3, 5);
BeanUtils.setProperty(pt1,"birthday.time", "111");
System.out.println(BeanUtils.getProperty(pt1,"birthday.time")); //结果:111
}
}
③、PropertyUtils类也可以操作对象的属性,但是与BeanUtils不同的是它不能进行自动类型转换。
例如:ReflectPoint类中的变量x属性为int类型,但是设置属性值的时候传入的参数类型却不能为String类型。
代码示例:
package cn.itcast.day1;
import org.apache.commons.beanutils.PropertyUtils;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
PropertyUtils.setProperty(pt1,"x", "9"); //会报错。
System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());
}
}
运行时会出现如下报错信息:
Exception in thread"main"java.lang.IllegalArgumentException: Cannot invoke cn.itcast.day1.ReflectPoint.setX on beanclass 'class cn.itcast.day1.ReflectPoint' - argument type mismatch - hadobjects of type "java.lang.String" but expected signature"int"
atorg.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2181)
atorg.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2097)
atorg.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1903)
atorg.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2010)
atorg.apache.commons.beanutils.PropertyUtils.setProperty(PropertyUtils.java:896)
atcn.itcast.day1.IntroSpectorTest.main(IntroSpectorTest.java:39)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
atjava.lang.reflect.Method.invoke(Method.java:597)
atorg.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2116)
... 5 more
处理方式:
需要将PropertyUtils.setProperty(pt1,"x", "9");中的属性值"9"改成int型的数值。
代码如下:
package cn.itcast.day1;
import org.apache.commons.beanutils.PropertyUtils;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3, 5);
PropertyUtils.setProperty(pt1,"x", 9); //改为int型之后恢复正常。
System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());
}
}