【一天一個基礎系列】- java之泛型篇
阿新 • • 發佈:2021-02-09
### 簡介
+ 說起各種高階語言,不得不談泛型,當我們在使用java集合的時候,會發現集合有個缺點:把一個物件“丟進”集合之後,集合就會“忘記”這個物件的資料型別,當再次取出該物件時,改物件的編譯型別就變成了`Object`型別
+ 問題1:集合對元素型別沒有任何限制,這樣可能會引發一些問題,比如建立一個用於儲存`A`物件的集合,但不小心把`B`物件放進去,會引發異常
+ 問題2: 由於把物件放進去時,集合對視了物件的狀態資訊,集合只知道它盛裝的是`Object`,因此去取集合元素後通常還需要進行強制型別裝換,這個過程不僅增加了程式設計的複雜度,還可能引發`CLassCastException`異常
+ 為解決以上問題,便引入“泛型”
+ java 5以後,java引入了“引數化型別”的概念,允許程式在建立集合時指定集合元素的型別
+ java 7之前,如果使用帶泛型的介面、類定義變數,那麼呼叫構造器建立物件時構造器的後面也必須帶泛型
+ 比如
```
//java 7之前
List list = new ArrayList();//後面的是必須帶上的
//java 7之後,"菱形"語法
List list = new ArrayList<>();
```
> 注:java 9允許在使用匿名內部類時使用菱形語法
+ 概念定義:允許在定義類、介面、方法時使用型別形參,這個型別形參將在宣告變數、建立物件、呼叫方式動態地指定
+ 我們來看一下定義泛型介面、類
```
/**
* 定義泛型介面,實質:允許在定義介面、類時什麼型別形參,
* 型別形參在整個介面、類體內可當成型別使用,幾乎所有可
* 使用普通型別的地方都可以使用這種型別形參
*/
public interface List {
void add(T x);
}
/**
* 定義
*
*
*/
@Data
public class Clazz {
private T a;
public Clazz(T a){
this.a = a;
}
}
//使用Clazz
pulic void method(){
Clazz clazz = new Clazz<>("");
}
```
+ 從泛型類派生子類
+ 當建立了帶泛型宣告的介面、父類之後,可以為該介面建立實現類,或從該父類派生子類,需要指出的是,當使用這些介面、父類時不能再包含泛型形參
```
//定義類Son類繼承Parent類
public class Son extends Parenet{
}
//使用Parent類時為T形參傳入String型別
public class Son extends Parent{
}
//使用Parent類時,沒有為T形參傳入實際的型別引數
public class Son extends Parent{
}
```
> 像這種使用Parent類時省略泛型的形式被稱為原始型別(raw type)
> 如果從Parent類派生子類,則在Parent類中所有使用T型別的地方都將被替換成String型別
+ 並不存在泛型類
+ `List`與`List` 創建出來的是同樣class檔案,它們在執行時總有同樣的類,故在靜態方法、靜態初始化塊或者靜態變數的生命和初始化中不允許使用泛型形參
```
public class R{
//錯誤,不能在靜態變數宣告中使用泛型形參
static T info;
//錯誤,不能再靜態方法宣告中使用泛型形參
public void foo(T p){
}
}
```
+ 型別萬用字元
+ 定義:為了表示各種泛型List的父類,可以使用型別萬用字元,型別萬用字元是一個問號(?),將一個問號作為型別實參傳給List集合,寫作:`List>`(意思是元素型別未知的List)。這個問號(?)被稱為萬用字元,它的元素型別可以匹配任何型別
+ 型別萬用字元的上限
+ 定義:當直接使用`List>·這種形式時,即表明這個List集合可以是任何泛型List的父類。但還有一種特殊的情形,程式不希望這個`List>`是任何泛型List的父類,只希望它代表某一類泛型List的父類
```
//定義上限為Parent類,表示泛型形參必須是Parent子類
List extends Parent>
```
+ 協變:對於更廣泛的泛型類來說,指定萬用字元上限就是為了支援型別型變。比如Foo是Bar的子類,這樣`A`就相當於`A extends Bar>`的子類,可以將`A`賦值給`A extends Bar>`型別的變數,這種型變方式被稱為協變
+ 型別萬用字元的下限
+ 定義:萬用字元的下限用` super型別>`的方式來指定,萬用字元下限的作用與萬用字元上限的作用恰好相反
```
//定義下限為Parent類
List super Parent>
```
+ 逆變:比如Foo是Bar的子類,當程式需要一個`A super Foo>`變數時,程式可以將`A`、`A