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());
}
}