Java高新技術——內省(JavaBean)

瞭解JavaBean

    內省對應的英文單詞爲IntroSpector,它主要用於對JavaBean進行操作,JavaBean是一種特殊的Java類,其中的某些方法符合某種命名規則,如果一個Java類中的一些方法符合某種命名規則,則可以把它當作JavaBean來使用。

    JavaBean是一種特殊的Java類,主要用於傳遞數據信息,這種java類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。

    如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象通常稱之爲值對象(Value Object,簡稱VO)。這些信息在類中用私有字段來存儲,如果讀取或設置這些字段的值,則需要通過一些相應的方法來訪問,大家覺得這些方法的名稱叫什麼好呢?JavaBean的屬性是根據其中的setter和getter方法來確定的,而不是根據其中的成員變量。如果方法名爲setId,中文意思即爲設置id,至於你把它存到哪個變量上,用管嗎?如果方法名爲getId,中文意思即爲獲取id,至於你從哪個變量上取,用管嗎?去掉set前綴,剩餘部分就是屬性名,如果剩餘部分的第二個字母是小寫的,則把剩餘部分的首字母改成小的。

例如:

setId()的屬性名-->id

isLast()的屬性名-->last

setCPU的屬性名是什麼?-->CPU

getUPS的屬性名是什麼?-->UPS

    總之,一個類被當作javaBean使用時,JavaBean的屬性是根據方法名推斷出來的,它根本看不到java類內部的成員變量。
    一個符合JavaBean特點的類可以當作普通類一樣進行使用,但把它當JavaBean用肯定需要帶來一些額外的好處,我們纔會去了解和應用JavaBean!好處如下:
    在Java EE開發中,經常要使用到JavaBean。很多環境就要求按JavaBean方式進行操作,別人都這麼用和要求這麼做,那你就沒什麼挑選的餘地!
    JDK中提供了對JavaBean進行操作的一些API,這套API就稱爲內省。如果要你自己去通過getX方法來訪問私有的x,怎麼做,有一定難度吧?用內省這套api操作JavaBean比用普通類的方式更方便。

對JavaBean的簡單內省操作

    主要用到了java.beans.PropertyDescriptor類,用來得到某個Class對象屬性集中的某個JavaBean屬性,然後調用getReadMethod()、getWriteMethod()方法獲得相應的get、set方法。

代碼示例:

Domain類:

package ustc.lichunchun.bean;

import java.util.Date;

public class ReflectPoint {
	private Date birthday = new Date();
	
	private int x;
	public int y;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "itcast";
	
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}


	@Override
	public String toString(){
		return str1 + ":" + str2 + ":" + str3;
	}


	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 Date getBirthday() {
		return birthday;
	}


	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
}
簡單內省操作:
package ustc.lichunchun.bean;

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";
		//"x"-->"X"-->"getX"-->MethodGetX-->
		
		getProperty(pt1, propertyName);
			
		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 pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodSetX = pd.getWriteMethod();
		methodSetX.invoke(pt1, value);
	}

	private static Object getProperty(Object pt1, String propertyName)
			throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodGetX = pd.getReadMethod();
		methodGetX.invoke(pt1);
	}

}

對JavaBean的複雜內省操作

    採用遍歷BeanInfo的所有屬性方式來查找和設置某個RefectPoint對象的x屬性。在程序中把一個類當作JavaBean來看,就是調用IntroSpector.getBeanInfo方法, 得到的BeanInfo對象封裝了把這個類當作JavaBean看的結果信息。

複雜內省操作:

package ustc.lichunchun.bean;

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";
		//"x"-->"X"-->"getX"-->MethodGetX-->
		
		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 pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodSetX = pd.getWriteMethod();
		methodSetX.invoke(pt1, value);
	}

	private static Object getProperty(Object pt1, String propertyName)
			throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		/*
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodGetX = pd.getReadMethod();
		methodGetX.invoke(pt1);
		*/
		
		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);
				break;
			}
		}
		return retVal;
	}

}

使用BeanUtils工具包操作JavaBean

    在前面內省例子的基礎上,用BeanUtils類先get原來設置好的屬性,再將其set爲一個新值。get屬性時返回的結果爲字符串,set屬性時可以接受任意類型的對象,通常使用字符串。
    用PropertyUtils類先get原來設置好的屬性,再將其set爲一個新值。get屬性時返回的結果爲該屬性本來的類型,set屬性時只接受該屬性本來的類型。

    注意:用這兩個類之前,需要在eclipse工程的lib文件夾中導入commons-beanutils.jar、commons-logging-1.1.jar兩個jar包,並且Add to BuildPath。

代碼示例:

package ustc.lichunchun.bean;

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;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

public class IntroSpectorTest {

	public static void main(String[] args) throws Exception {
		ReflectPoint pt1 = new ReflectPoint(3, 5);
		
		String propertyName = "x";
		//"x"-->"X"-->"getX"-->MethodGetX-->
		
		Object retVal = getProperty(pt1, propertyName);
		System.out.println(retVal);
		
		Object value = 7;
		setProperty(pt1, propertyName, value);
		
		System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());//String
		BeanUtils.setProperty(pt1, "x", "9");
		System.out.println(pt1.getX());
		
		/*
		Map map = {name:"zxx",age:18};//java7的新特性
		BeanUtils.setProperty(map, "name", "lcc");
		*/
		
		BeanUtils.setProperty(pt1, "birthday.time", "111");//支持屬性鏈
		System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
		
		PropertyUtils.setProperty(pt1, "x", 23);
		System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());//Integer
		
		/*
		BeanUtils和PropertyUtils的區別:
		BeanUtils以字符串形式對JavaBean進行操作,也可以操作Map類,並且可以講JavaBean和Map進行互相轉換(describe、populate)
		PropertyUtils以JavaBean屬性本身的數據類型進行操作		
		 */
	}

	private static void setProperty(Object pt1, String propertyName, Object value)
			throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodSetX = pd.getWriteMethod();
		methodSetX.invoke(pt1, value);
	}

	private static Object getProperty(Object pt1, String propertyName)
			throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		/*
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		Method methodGetX = pd.getReadMethod();
		methodGetX.invoke(pt1);
		*/
		
		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);
				break;
			}
		}
		return retVal;
	}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章