--------------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(){
}
}
3、Retention和RetentionPolicy
在註解中,可以使用Retention定義一個註解的保存範圍,Retention的定義中有一個value屬性,類型爲RetentionPolicy,RetentionPolicy中包含的範圍有三種
(1)SOURCE:此註解類型的信息指揮保存在.java文件中,編譯之後不保存。
(2)CLASS:此類型的註解保存在.java與.class文件中,此類使用時,信息不回加載到虛擬機中,如果註解在聲明時未指定範圍,默認爲此範圍。
(3)RUNTIME:此類型的註解保存在.java與.class文件中,也會加載到虛擬機。
4、Target註解,用來指定註解使用的位置
(1)public static final ElementType PACKAGE:只能用在包聲明
(2)public static final ElementTypeFIELD:只能用在字段聲明(包括枚舉常量)上
(3)public static final ElementTypeANNOTATION_TYPE:只能用在註釋類型聲明上
(4)public static final ElementTypeCONSIRUCTOR:只能用在構造器聲明上
(5)public static final ElementTypeMETHOD只能用在方法聲明上
(6)public static final ElementTypePARAMETER只能用在參數聲明上
(7)public static final ElementTypeTYPE只能用在類、接口、或枚舉聲明上
(8)public 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);
}
}
}