Java基礎加強_內省、註解、泛型

Java基礎加強---day02

五、內省

    JavaBeanJavaBean是一種特殊的Java類,主要用於傳遞數據信息,這種Java類中的方法主要用於訪問私有的字段,並且方法名符合某種命名規則。當某個java類中的一些方法符合某種命名規則,那麼就可以把它當做JavaBean來使用。

    如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象通常稱爲值對象(Value Object)。這些信息在類中用私有字段來存儲,如果要讀取或者設置這些字段的值,那麼需要通過一些相應的方法來訪問。

    去掉前綴(set、get)後,剩下的部分就是屬性名,如果剩餘部分的第二個字母是小寫的,則把剩餘部分的首字母改爲小寫的;如果第二個字母是大寫的,第一個字母保留大寫。

    總之:一個JavaBean類的屬性名可以根據方法名推斷出來,並且我們根本看不到java類內部的成員變量

    由於JavaBean廣泛的應用性,Eclipse有專門的快捷鍵產生,即getter和setter。

    JavaBean的好處:

    1、在JavaEE開發中,經常要使用到JavaBean,很多環境要求按照JavaBean,所以JavaBean很重要!

    2、JDK中提供了對JavaBean進行操作的一些API,所以操作相對簡單方便,這一套API就稱爲內省。

    內省:對應的英文單詞爲:IntroSpector,有內部視察的意思,主要用於對JavaBean的操作。java提供的API爲:PropertyDescriptor。但PropertyDescriptor類對JavaBean的操作過於複雜,也可以通過導入BeanUtils工具包對JavaBean進行內省操作。

    萬事萬物都應該都應該用一個東西來描述,BeanInfo是專門用於描述JavaBean的一個類,也可以通過遍歷BeanInfo中所有屬性的方式對JavaBean進行描述,IntroSpector.getBeanInfo(<?>class),獲取BeanInfo對象。但這種方法操作較爲麻煩,可以作爲了解。

    導入方式:選中工程,右鍵-->buildPath-->Configure  buildPath 然後導入相應的工具包,即可。

    產生getter和setter的方式:在類中的空白處,右鍵-->Source-->Generate  Getters and Setters,然後選中相應字段,即可。

    抽取方法的方式:選中要抽取成爲方法的代碼,右鍵-->refactor-->Extract Method,即可。

下面代碼體現:

1、內省的演示:

package itheima.day08;

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 com.sun.xml.internal.fastinfoset.sax.Properties;

import itheima.day07.ReflectPoint;

public class IntroSpectorTest {

	public static void main(String[] args) throws Exception {
		
//		提供設置、獲取某個字段的類 就是JavaBean
		ReflectPoint pt1 = new ReflectPoint(3, 5);
		
//		獲取讀取一個字段的方法
		String propertyName = "x";
		Object returnValue = getProperty(pt1, propertyName);
		System.out.println(returnValue);//3
		
//		設置一個字段的值
		Object value =7;
		setProperty(pt1,propertyName,value);
		
//		使用BeanUtils工具包  
		System.out.println(BeanUtils.getProperty(pt1, "x"));
		
//		BeanUtils工具包的方法更加簡便
		
		System.out.println(pt1.getX());//7
		
//		BeanUtils.setProperty(pt1, "birthday.time", "111");//級聯操作 
		
//		 System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));  
	}
	
	private static void setProperty(ReflectPoint pt1, String propertyName,
			Object value) throws Exception {
//		PropertyDescriptor(String propertyName, Class<?> beanClass)
		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, IllegalArgumentException, InvocationTargetException{

//		操作JavaBean的API,內省
//		PropertyDescriptor(String propertyName, Class<?> beanClass)
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		
//		獲取應用於讀取字段屬性值的方法
		Method methodGetX = pd.getReadMethod();
		
//		關聯具體的對象
		Object returnValue = methodGetX.invoke(pt1);
		
//		這是早期的做法
//		BeanInfo類專門用於描述JavaBean
		BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
		
//		獲取JavaBean中所有的屬性值
		PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors();
		
		Object retvalue =null;
		for(PropertyDescriptor pd1:pds){
//			尋找我們想要的字段名
			if(pd1.getName().equals(propertyName)){
				Method methodGetx1 = pd.getReadMethod();
				retvalue= methodGetx1.invoke(pt1);
			}
		}
		return returnValue;
	}
}

六、註解

    註解:註解相當於一種標記,在程序中加了註解就等於爲程序打上了某種標記;是註解是JDK1.5的一個重要新特性。

    JDK中自帶有三個註解:

    1、@SupressWarning:取消編譯器提出的警告,只在源文件時期中有效。

    2、@Deprecated:提示元素是過時的,直到運行期都有效。

    3、@Override:表示覆蓋父類中的方法,只在源文件時期有效,只能用在方法上。

    註解相當於程序中要調用的一個類,要在源程序中應用某個註解,得先有這個註解類;好比要調用某個類,必須先開發好這個類。註解的應用結構如下圖所示:


    @Retention,元註解,用在註解中的註解,有三個取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME;分別對應:java源文件、class文件、內存中的字節碼。

    @Target:指示註釋類型所適用的程序元素的種類。如果註釋類型聲明中不存在 Target 元註釋,則聲明的類型可以用在任一程序元素上。如果存在這樣的元註釋,則編譯器強制實施指定的使用限制。可以是Filed(字段)、Method(方法)、Type(類型,包括類、接口、註解等)。

    註解的屬性:註解本身就是給給源程序打上某種標記,則註解的屬性就是標記中的標記,即更具體的標記。

下面代碼演示:

註解類:

package itheima.day08;

import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;  
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import itheima.day07.EnumTest;

//源註解,指明該註解類的生命週期
@Retention(RetentionPolicy.RUNTIME)

//源註解,指明註解類可以用在什麼類型的數據上,即使用目標
@Target({ElementType.METHOD,ElementType.TYPE})

public @interface ItcastAnnotation {
	
//	註解的屬性
	String color() default "bule";
	
	String value();
//	 註解的屬性有默認值時,應用時可以不必指定
	int[] arrayAttr() default {3,2,1};
	
//	帶枚舉的註解
	EnumTest.TrafficLamp lam() default EnumTest.TrafficLamp.RED;
}

應用註解的類:

package itheima.day08;

//使用"註解類"的類
//在使用註解類時,必須給未初始化的屬性賦值
@ItcastAnnotation(color ="red", value = "abc")
public class AnnotationTest {
	
//	取消警告
	@SuppressWarnings("deprecated")
	
//	只有value一個屬性待賦值時,可以省略屬性名
	@ItcastAnnotation("xyz")
	
	public static void main(String[] args) {
		
//		過時的方法
		System.runFinalizersOnExit(true);
		
//		MyEclipse提示該方法過時
		AnnotationTest.sayHello();
		
//		對使用註解類的類進行反射
		if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
			
//			通過反射的形式獲取到註解類
			ItcastAnnotation annotation = 
					(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);

//			@itheima.day08.ItcastAnnotation(color=red, lam=RED, arrayAttr=[3, 2, 1], value=abc)
			System.out.println(annotation);
			
//			獲取到註解類之後,可以獲取註解類中的屬性字段
			System.out.println(annotation.color());
			System.out.println(annotation.value());
			System.out.println(annotation.arrayAttr().length); 
			System.out.println(annotation.lam().nextLamp().name());  
		}
		
	}
	
//	給該方法打上過時的標記,使用的是JDK提供的註解類
	@Deprecated
	public static void sayHello(){
		System.out.println("hello itheima");
	}
}

七、泛型

    泛型:泛型是提供給javac編譯器使用的,可以限定集合中的輸入類型,讓編譯器擋住源程序中的非法輸入,編譯器編譯帶類型說明的集合時會去除掉“類型”信息,使程序運行效率不受影響,對於參數化的泛型類型,getClass()方法的返回值和原始類型完全一樣。由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,例如,用反射得到集合,再調用其add方法即可。

    泛型是JDK1.5的一個新特性,沒有泛型時,集合中通過Object提供擴展性,但什麼類型的對象都可以往同一個集合中放,這就容易引起操作集合中元素時發生一些異常。指定了泛型後,集合中只能放進特定的類型元素,提高了代碼的安全性。

    泛型的特定術語:

    ArrayList<E>:泛型類型;E稱爲類型變量或者類型參數;

   ArrayList<Integer>稱爲參數化的類型;<>稱爲typeof;ArrayList稱爲原始類型。

    參數化類型可以引用一個原始類型的對象,編譯報告警告;如:

    Collection<String>c = new Vector();//兼容JDK1.4以前編寫的程序;

    原始類型可以引用一個參數化類型的對象,編譯報告警告;

    Collectionc = new Vector<String>();//原來的方法接受一個集合參數,新的類型也要能傳進去。

    上限:? extends E。

    下限:? super E。

    關於泛型,在集合那一章中有詳細的介紹,在此不再贅述!

下面代碼演示:

package itheima.day08;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;

public class GenericTest {
	
	public static void main(String[] args) throws Exception {
		
//		在泛型出現之前,用Object提供擴展性
//		面向接口的編程
		Collection collection1 = new ArrayList();
		
//		使用Object提供擴展性,弊端很明顯:什麼東西都可以往集合中放
		collection1.add(1);
		collection1.add(1.2);
		collection1.add("abc");
		System.out.println(collection1.size());
		
//		JDK1.5版本以後,用泛型限定存入集合的類型
		Collection<String> collection2 = new ArrayList<String>();
		collection2.add("abcd");
		
//		編譯通不過,把安全問題扼殺在編譯時期
//		collection2.add(1.2);
		System.out.println(collection2.size());
		
//		可以使用反射技術透過編譯器
		Constructor<String> constructor1 =
				String.class.getConstructor(StringBuffer.class);
		String str2 = constructor1.newInstance(new StringBuffer("abc"));
		System.out.println(str2);
		
		ArrayList<Integer> collection3 = new ArrayList<Integer>();
		
//		同一份字節碼,說明字節碼與泛型無關,泛型只是給編譯器看門的一個道具,僅此而已
		System.out.println(collection2.getClass()==collection3.getClass());//true
		
//		用反射透過編譯器
		collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
		System.out.println(collection3.get(0));
	}
}


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