天天看點

Java高新技術之JavaBean(内省 IntroSpector)

一、Javabean

1.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類内部的成員變量。

2.一個符合JavaBean特點的類可以當作普通類一樣進行使用,但把它當JavaBean用肯定需要帶來一些額外的好處,我們才會去了解和應用JavaBean!好處如下:

  • 在Java EE開發中,經常要使用到JavaBean。很多環境就要求按JavaBean方式進行操作,别人都這麼用和要求這麼做,那你就沒什麼挑選的餘地!
  • JDK中提供了對JavaBean進行操作的一些API,這套API就稱為内省。如果要你自己去通過getX方法來通路私有的x,怎麼做,有一定難度吧?用内省這套api操作JavaBean比用普通類的方式更友善。
二、PropertyDescriptor  BeanInfo BeanUtils PropertyUtils操作javabean  見代碼所示:
import java.util.Date;

public class Person
{
	  private String name;
	  private int age;
	  private Date birthday=new Date();//這裡要建立對象!
	
    public Date getBirthday()
	{
		return birthday;
	}
	public void setBirthday(Date birthday)
	{
		this.birthday = birthday;
	}
	public Person(String name, int age)
	{
		super();
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public int getAge()
	{
		return age;
	}
	public void setAge(int age)
	{
		this.age = age;
	}
	
	@Override
	public String toString()
	{
		return this.name+" "+this.age+" "+this.birthday;
	}
  
  
}
           
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
{

	/**
	 * 各種類操作javabean
	 */
	public static void main(String[] args)throws Exception
	{
		Person p=new Person("張三",23);
		String propertyName="name";
		//1.以下使用PropertyDescriptor操作javabean
		getProperty(p, propertyName);
		
		Object val="張凱";
		setProperty(p, propertyName, val);
		
		//2.以下使用BeanInfo操作javabean
		getPropertyByBeanInfo(p, propertyName);
		
		//3.以下使用BeanUtils操作javabean。
		BeanUtils.setProperty(p, propertyName,"李四" );
		//這是屬性鍊,birthday是Date類型的,Date中有setTime(long time)方法
		BeanUtils.setProperty(p, "birthday.time","11111");
		System.out.println(BeanUtils.getProperty(p, "birthday.time"));
		//BeanUtils操作中參數是String類型的 傳回結果也是String類型
		System.out.println(BeanUtils.getProperty(p, "birthday.time").getClass().getName());
		
		//4.PropertyUtils操作javabean
		PropertyUtils.setProperty(p, "name", "lily");
		PropertyUtils.setProperty(p, "age", 30);//傳入是是int
		System.out.println(PropertyUtils.getProperty(p, "age").getClass().getName());//傳回是Integer
		PropertyUtils.setProperty(p, "birthday.time", 10000);
		System.out.println(p);
		

	}
	public static void getPropertyByBeanInfo(Person p, String propertyName)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException
	{
		BeanInfo beanInfo=Introspector.getBeanInfo(p.getClass());
		PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
		//周遊數組找到指定屬性
		for(PropertyDescriptor pd:pds)
		{
			if(pd.getName().equals(propertyName))
			{
			  System.out.println(pd.getReadMethod().invoke(p));
				break;
			}
		}
	}
    //設定屬性方法
	public static void setProperty(Person p, String propertyName, Object val)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException
	{
		PropertyDescriptor pd1=new PropertyDescriptor(propertyName,p.getClass());
		Method methodSet=pd1.getWriteMethod();
		methodSet.invoke(p, val);//調用set方法把name值設定為“張凱”
		System.out.println(p);
	}
	
	//得到屬性方法
	private static void getProperty(Person p, String propertyName)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException
	{   
		//擷取javaBean的屬性描述
		PropertyDescriptor pd=new PropertyDescriptor(propertyName,p.getClass());
		//得到方法
		Method methodGet=pd.getReadMethod();
		System.out.println(methodGet.invoke(p));//調用方法
	}

}
           
三、其他

用struts的疊代标簽不能疊代出枚舉元素的屬性,而用jstl的疊代标簽則可以。采用BeanUtils去擷取帶有抽象方法的枚舉類的成員對象的屬性時,會出現錯誤,要自己用内省加暴力反射方式才可以擷取。主要原因是枚舉類的抽象子類不是public類型的。

public static void main(String[] args) {
		// TODO Auto-generated method stub
		/*System.out.println(
		PropertyUtils.getProperty(Sex.NONE, "title"));*/
	
		Object bean = Sex.NONE;
		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(bean.getClass());
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	
		PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
		for(PropertyDescriptor property:properties)
		{
			if(property.getName().equals("title"))
			{
				Method method = property.getReadMethod();
				method.setAccessible(true);
				Object retVal;
				try {
					retVal = method.invoke(bean, null);
    				System.out.println(retVal);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}		
	}