黑馬程序員--泛型與註解

--------------android培訓java培訓、學習型技術博客、期待與您交流! --------------

 

一、泛型(Generic)

泛型:就是指在對象建立時不指定類中屬性的具體類型,而由外部在聲明及實例化對象時指定具體的類型。

      由於添加的元素類型不同,所以元素類型會進行自動提示爲Object,所以取出集合中的元素時需要強轉,但是類型各異,所以就會產生ClassCastException(類型轉換異常),爲了避免該種潛在威脅,就出現了一種安全機制--泛型。

泛型只是編譯時的概念,是功編譯器進行語法檢查用的。主要目的有兩個方面:

    1、努力將運行時異常轉換成編譯時錯誤,減少運行時異常數量。

    2、解決模板編程的問題。

       泛型採用的是<>標記,在程序中,只要用到了帶有<>的類或者接口,就要明確傳入的具體引用數據類型 ,其實<>就是一個用於接收具體引用數據類型的參數範圍,如ArrayList中存入的元素時String,定義格式爲: List<String> list = new ArrayList<String>();。

泛型的原理:

     1、泛型的擦除:由於泛型是從jdk1.5開始的,所以爲了兼容前面的類加載器,所以編譯後的字節碼是不存在泛型的概念的。

      2、泛型的補償機制:泛型已經擦除,所以就產生了一種補償機制,使用元素的getClass方法,得到類型後,就不需要強轉了。

泛型是實現是在編譯時期檢查類型,當類型檢查完成後,就進行泛型擦除,然後再進行泛型補償,達到將運行時異常轉化爲編譯時異常,與減少強轉的目的。

 

類型參數中的通配符約束

<?>允許所有泛型的引用調用,參數未指定泛型默認爲<?>

<? extends 類名>只允許該類及其子類的引用調用

<? super 類名>只允許該類以及其父類的引用調用

<? extends 接口名>只允許該接口以及該接口的實現類的引用調用

 

泛型方法中的通配符約束

<?>允許所有泛型的引用調用

<? extends 類名>只允許該類及其子類的引用調用

<? extends 接口名>只允許該接口以及該接口的實現類的引用調用

<? extends 接口名&類名>只允許泛型爲繼承該類又實現該接口的類

 

泛型類中的通配符約束與泛型方法相同

編寫泛型類需要注意的地方:

1、靜態方法中不能使用類的泛型,因爲泛型類中的泛型在創建類的對象是被替換爲確定類型。靜態方法可以通過類名直接訪問,還沒有傳入參數,因此會報錯。

2、不能再Catch字句中使用泛型,因爲編譯時,如果try字句拋出的是已檢查一次,編譯器無法確定Catch中能不能捕獲該異常。

 泛型方法定義示例

package cn.itheima.blog7;

import java.util.ArrayList;
import java.util.List;

public class GenericMethodDefine {

	/**
	 * 自定義泛型方法演示(下限,上限等)
	 */
	public static void main(String[] args) {
		//創建三個對象數組
		Number[] a1 = new Number[2];
		Double[] a2 = new Double[2];
		String[] a3 = new String[2];
		
		//創建兩個集合
		List<Number> l1= new ArrayList<Number>();
		List<String> l2 = new ArrayList<String>();
		
		//將數組中的數據添加到集合中
		array2List(a1, l1);
		array2List(a2, l1);
		array2List(a3, l2);
	}
	 //Number及其子類
	public static <T extends Number> void array2List(T[] a, List<T> l){
		for(T o : a){
			l.add(o);
		}
		System.out.println(l);
	}
	//既是Number子類又是Comparable的實現類
	/*public static <T extends Number & Comparable> void array2List(List<T> l, T[] a){
		for(T o : a){
			l.add(o);
		}
	}*/

	//Comparable的實現類
	public static <T extends Comparable> void array2List(T[] a, List<T> l){
		for(T o : a){
			l.add(o);
		}
		System.out.println(l);
	}
}


 

二、註解(Annotation)

 

註解:相當於一個標記,加上了註解等於爲程序加入了某種標記,開發工具和其他程序通過反射來了解類及個元素上有無標記,有標記就做該標記對應的操作。

註解的位置:加在包、類,字段,方法,方法的參數以及局部變量上

1、java.lang包中最基本的三種註解

        @Override:主要用在方法覆蓋時使用,用於保證方法覆蓋的正確性。當子類覆蓋方法不正確時,就會報錯。

        @Deprecated:用來聲明一個不建議使用的方法,如果在程序中使用了該方法,則在編譯時將出現過時警告,在Eclipse中會劃線。隨着Jdk的升級,許多方法會過時,但是爲了顧及以前用該方法開發的項目,又不能刪除該方法,但是又不建議使用,因此就會使用該註解。

        @SuppressWarning:用來壓制警告。在前面的泛型中,若一個類聲明時沒有指明泛型,則肯定在編譯時產生警告,用了@SuppressWarning就不會顯示這些警告。

@SuppressWarning中的關鍵字

 

2、自定義Annotation

      定義格式:

    [public] @interface  名稱{

       數據類型 變量名稱();

   }

    在程序中只要使用了@interface聲明Annotation,那麼此Annotation實際上相當於實現了lang包下的Annotation接口

向Annotation中設置內容,即爲註解添加屬性

     Annotation中設置內容類似接口中函數的定義,如添加一個name屬性,類型爲String,可寫爲[public] String name();,其中的public爲默認值,就像接口默認爲public abstract。也可以爲設置的內容添加默認值,格式爲[public] String name default 默認值。

     自定義時,參數類型是有範圍的, 八種基本數據類型,String,Class,枚舉,註解及前面五種類型的數組。下面演示自定義簡單註解及其使用:

package cn.itheima.blog7;

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

enum Weekday{
	SUN,MON,TUE,WEN,THU,FRI,SAT;
}

/*
 * 演示String,基本數據,數組,class
 */
//@Retention的使用
@Retention(RetentionPolicy.RUNTIME)

//@Tatget的使用
@Target(value = ElementType.METHOD)
@interface  ItheimaAnnotation {
	String name();
	int length();
	Class clazz();
	
}

/*
 * 演示數組,枚舉,註解的使用,並設定默認值
 */
@interface  ItheimaAnnotation_2{
	//當數組中的值爲一個時,可以不用花括號包裝
	int[] arrayAttr() default {1}/*1*/;
	Weekday value();
	SuppressWarnings warning() default @SuppressWarnings("deprecation");
}
package cn.itheima.blog7;

public class ItheimaAnnotationDemo {

	/**
	 * 演示自定義Annotation的使用
	 */
	public static void main(String[] args) {
		show();
	}
	
	@ItheimaAnnotation(name = "heima", length = 5, clazz = String.class)
	//當屬性爲value,且其他屬性有默認值時,可以省略value=不寫,直接傳入數值
	@ItheimaAnnotation_2(Weekday.FRI)
	public static void show(){
		
	}

}

 

3RetentionRetentionPolicy
在註解中,可以使用Retention定義一個註解的保存範圍,Retention的定義中有一個value屬性,類型爲RetentionPolicyRetentionPolicy中包含的範圍有三種
1SOURCE:此註解類型的信息指揮保存在.java文件中,編譯之後不保存。
2CLASS:此類型的註解保存在.java.class文件中,此類使用時,信息不回加載到虛擬機中,如果註解在聲明時未指定範圍,默認爲此範圍。
3RUNTIME:此類型的註解保存在.java.class文件中,也會加載到虛擬機。

4Target註解,用來指定註解使用的位置
1public static final ElementType PACKAGE:只能用在包聲明
2public static final ElementTypeFIELD:只能用在字段聲明(包括枚舉常量)上
3public static final ElementTypeANNOTATION_TYPE:只能用在註釋類型聲明上
4public static final ElementTypeCONSIRUCTOR:只能用在構造器聲明上
5public static final ElementTypeMETHOD只能用在方法聲明上
6public static final ElementTypePARAMETER只能用在參數聲明上
7public static final ElementTypeTYPE只能用在類、接口、或枚舉聲明上
8public static final ElementType LOCAL_VARIABLE只能用在局部變量聲明上

5、通過反射取得Annotation
步驟:
     (1)取得運用註解的類
     (2)取得類中運用註解的部分,如方法
     (3)取得註解內容

    結合前面自定義註解演示反射取得Annotation

package cn.itheima.blog7;

import java.lang.reflect.Method;

public class ReflectAnnotation {

	/**
	 * @param args
	 * @throws Exception 
	 * 獲取Annotation指定屬性的值
	 */
	public static void main(String[] args) throws Exception {
		//得到運用註釋的類
		Class c = Class.forName("cn.itheima.blog7.ItheimaAnnotationDemo");
		//得到類中運用註解的方法
		Method method = c.getMethod("show");
		//若指定的註釋類型運用在此方法上
		if(method.isAnnotationPresent(ItheimaAnnotation.class)){
			//獲取註釋類型對象
			ItheimaAnnotation ia = method.getAnnotation(ItheimaAnnotation.class);
			//取值
			String name = ia.name();
			System.out.println(name);
		}
	}

}


 

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