一、泛型的好處:
①適用于多種資料型別,執行相同代碼,
②可在編碼程序中定義資料型別,不需要進行強制型別轉換,以及在插入資料型別時就可在編譯期間就發現,而不是在運行期間例外報錯,
二、泛型定義
泛型包含泛型類、泛型介面和泛型方法,
1、泛型類,在創建泛型類時,需要定義泛型,(T字符不限,也可以使用K等等,多個泛型可使用逗號間隔<T,K>)
/**
* 泛型類,可以定義T或者K等等
* 也可以定義多個<T,K>
*/
public class GennericClass<T> {
private T t;
//這個不是泛型方法,只是參考的泛型引數再泛型類進行了宣告
public GennericClass(T t) {
this.t = t;
}
//這個不是泛型方法,只是回傳的泛型在泛型類進行了宣告
public T setData() {
return this.t;
}
}
2、泛型介面的定義
①泛型介面:
interface Gennertor<T>{
public T next();
}
②泛型介面實作有兩種,一種實作泛型引數,一種不實作泛型引數,代碼如下:
第一種:不實作泛型引數
class ImplGenertor<T> implements Gennertor<T>{
@Override
public T next() {
// TODO Auto-generated method stub
return null;
}
}
第二種:實作泛型引數
class ImplGenertor2 implements Gennertor<String>{
@Override
public String next() {
// TODO Auto-generated method stub
return null;
}
}
3、泛型方法,是完全獨立的,可存在在于普通類、泛型類或者泛型介面中,
①如何宣告一個泛型方法,在回傳值型別宣告前添加<泛型>,
②只有宣告<泛型>的方法,才是泛型方法,
代碼如下:
public <K> K lower(K k) {
return k;
};
public <E,F> E show(E e, F f) {
return e;
};
三、限定型別變數
1、限定泛型,該泛型必須具備某個類的方法,
例:一個泛型可使用compareTo比較大小,讓
/**
* 如何讓a一定具有compareTo();對T進行限定<T extends Comparable>
* 給T限定一個類或者一個介面:T extends ArrayList 或者T extends Comparable
* T只能實作一個類(類必須卸載最前面),但是T可以實作多個介面:T extends ArrayList&Comparable&Serializable
* @return
*/
public static <T extends ArrayList&Comparable&Serializable> T min (T a, T b) {
if (a.compareTo(b)>0) return a; else return b;
}
四、泛型的局限性
1、不能用基本型別的實體化為泛型的型別,必須使用封包后的參考物件,
例:int型別,參考Integer
代碼如下:
class Gen extends GennericClass<Integer>{
}
2、泛型類中的靜態變數和靜態方法不能參考泛型類定義的泛型,會編譯報錯,但是可定義不同于泛型類宣告泛型的靜態泛型方法,
public class GennericClass<T> {
//編譯報錯
private static T tt;
//編譯報錯
public static T getData(T t) { return t; }
//編譯正常:不同于泛型類宣告泛型的靜態泛型方法
public <K> K lower(K k) { return k; };
}
上述代碼泛型類中的靜態變數和靜態方法編譯報錯原因是因為其是在物件實體化之前就生成的,此時虛擬機也不知道T是什么,
3、可以宣告泛型陣列,但是不能實體化泛型陣列
List<String>[] a;//可以使用
List<String>[] b = new List<String>[10];//報錯
五、泛型通配符?和extends(上界)與super(下限)的關系
環境:
創建類:Letter、A、AA、A2、B、BB、BB
AAA—>AA—>A—>Letter(extends關系從左到右依次子類到父類)
A2–>A–>Letter
BBB—>BB—>B—>Letter(extends關系從左到右依次子類到父類)

1、<? extends E>為Upper Bound(上限) 的通配符,用來限制元素的型別的上限,
實體:
List<? extends A> list = new ArrayList<A>;
//List<? extends A> list = new ArrayList<AA>();
//List<? extends A> list = new ArrayList<Letter>();//編譯報錯
//List<? extends A> list = new ArrayList<B>();//編譯報錯
由此可見該集合中的元素上限為A型別,即其元素只能為A或者為A的子類,因此實體①②未編譯報錯,
Add:
因為集合list中裝入的元素是A型別的,因此我們裝入A或其子元素型別AA.例:
list.add(new A());//編譯報錯:The method add(capture#1-of ? extends A) in the type List<capture#1-of ? extends A> is not applicable for the arguments (A)
list.add(new AA());//編譯報錯
list.add(new A2());//編譯報錯
報錯原因:因為<? extends A>只是告訴編譯器其集合中元素上限為A,而未告知其具體型別,
list的實體物件可為 new ArrayList();也可以為 new ArrayList()或者ArrayList();等等其集合元素為A的子類的集合物件
例:當list的實體物件元素型別為AA時,此時添加的實體物件為其父類A,(很明顯此時型別不兼容)
因此型別的不確定,為了其型別安全,編譯器只能禁止其添加物件
Get:
A a1 = list.get(index);
*而獲取則無論list集合物件的元素指向哪一個,都屬于A的子類,因此集合的讀取是允許執行的
2、<? super E>為Lower Bound(下限)通配符,用來限制該元素型別的下限,
例:
List<? super A> lower = new ArrayList<A>;
//List<? super A> lower = new ArrayList<Letter>;
//List<? super A> lower = new ArrayList<Object>;
//List<? super A> lower = new ArrayList<AA>;//編譯報錯:Type mismatch: cannot convert from ArrayList<AA> to List<? super A>
*由上:其實體物件物件元素若為A的子類則編譯不通過,其實體物件的元素A為其下限
Add:
例:
lower .add(new A());
lower.add(new AA());
lower.add(new Letter());//編譯報錯:The method add(capture#6-of ? super A) in the type List<capture#6-of ? super A> is not applicable for the arguments (Letter)
*由上:因為編譯器已經知道該集合內的元素物件的上限為A,因此A和A的子類均可添加,
而Letter為A的父類,編譯器無法識別new Array,
Get:
Object object = lower.get(0);
*因為不知道具體型別,所以默認都是Object,需要向下強轉,而泛型的目的是為了避免強制型別轉換的繁瑣操作,
PECS法則:生產者(Producer)使用extends,消費者(Consumer)使用super
1、生產者:資料提供者
如果你需要一個提供E型別元素的集合,使用泛型通配符<? extends E>,它好比一個生產者,可以提供資料,
2、消費者:資料消費者
如果你需要一個只能裝入E型別元素的集合,使用泛型通配符<? super E>,它好比一個消費者,可以消費你提供的資料,
3、既是生產者也是消費者
既要存盤又要讀取,那就別使用泛型通配符,
方知
2021-02-28
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/265348.html
標籤:其他
下一篇:開源資產/漏洞管理平臺使用測評
