java模型给泛型_【一天一个基础系列】- java之泛型篇
java 5以后,java引入了“參數(shù)化類型”的概念,允許程序在創(chuàng)建集合時指定集合元素的類型
java 7之前,如果使用帶泛型的接口、類定義變量,那么調用構造器創(chuàng)建對象時構造器的后面也必須帶泛型
比如
//java 7之前
List list = new ArrayList();//后面的是必須帶上的
//java 7之后,"菱形"語法
List list = new ArrayList<>();
注:java 9允許在使用匿名內部類時使用菱形語法
概念定義:允許在定義類、接口、方法時使用類型形參,這個類型形參將在聲明變量、創(chuàng)建對象、調用方式動態(tài)地指定
我們來看一下定義泛型接口、類
/**
* 定義泛型接口,實質:允許在定義接口、類時什么類型形參,
* 類型形參在整個接口、類體內可當成類型使用,幾乎所有可
* 使用普通類型的地方都可以使用這種類型形參
*/
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<>("");
}
從泛型類派生子類
當創(chuàng)建了帶泛型聲明的接口、父類之后,可以為該接口創(chuàng)建實現(xiàn)類,或從該父類派生子類,需要指出的是,當使用這些接口、父類時不能再包含泛型形參
//定義類Son類繼承Parent類
public class Son extends Parenet{
}
//使用Parent類時為T形參傳入String類型
public class Son extends Parent{
}
//使用Parent類時,沒有為T形參傳入實際的類型參數(shù)
public class Son extends Parent{
}
像這種使用Parent類時省略泛型的形式被稱為原始類型(raw type)
如果從Parent類派生子類,則在Parent類中所有使用T類型的地方都將被替換成String類型
并不存在泛型類
List與List 創(chuàng)建出來的是同樣class文件,它們在運行時總有同樣的類,故在靜態(tài)方法、靜態(tài)初始化塊或者靜態(tài)變量的生命和初始化中不允許使用泛型形參
public class R{
//錯誤,不能在靜態(tài)變量聲明中使用泛型形參
static T info;
//錯誤,不能再靜態(tài)方法聲明中使用泛型形參
public void foo(T p){
}
}
類型通配符
定義:為了表示各種泛型List的父類,可以使用類型通配符,類型通配符是一個問號(?),將一個問號作為類型實參傳給List集合,寫作:List>(意思是元素類型未知的List)。這個問號(?)被稱為通配符,它的元素類型可以匹配任何類型
類型通配符的上限
定義:當直接使用List>·這種形式時,即表明這個List集合可以是任何泛型List的父類。但還有一種特殊的情形,程序不希望這個List>`是任何泛型List的父類,只希望它代表某一類泛型List的父類
//定義上限為Parent類,表示泛型形參必須是Parent子類
List extends Parent>
協(xié)變:對于更廣泛的泛型類來說,指定通配符上限就是為了支持類型型變。比如Foo是Bar的子類,這樣A就相當于A extends Bar>的子類,可以將A賦值給A extends Bar>類型的變量,這種型變方式被稱為協(xié)變
類型通配符的下限
定義:通配符的下限用 super類型>的方式來指定,通配符下限的作用與通配符上限的作用恰好相反
//定義下限為Parent類
List super Parent>
逆變:比如Foo是Bar的子類,當程序需要一個A super Foo>變量時,程序可以將A、A賦值給A super Foo>類型的變量,這種型變方式被稱為逆變
對于逆變的泛型而言,它只能調用泛型類型作為參數(shù)的方法;而不能調用泛型類型作為返回值類型的方法。口訣是:逆變只進不出
泛型方法
定義:所謂泛型方法,就是在聲明方法時定義一個或多個泛型形參,與類、接口中使用泛型參數(shù)不同的是,方法中的泛型參數(shù)無須顯式傳入實際類型參數(shù)修飾符返回值類型 方法名(形參列表){
//TODO
}
泛型方法和類型通配符的區(qū)別
使用通配符比使用泛型方法(在方法簽名中顯式聲明泛型形參)更加清晰和準確
類型通配符既可以在方法簽名中定義形參的類型,也可以用于定義變量的類型;但泛型方法中的泛型形參必須在對應方法中顯式聲明
大多數(shù)時候都可以使用泛型方法來代替類型通配符//使用類型通配符
public interface Collection{
void add(Collection> p);
void delete(Collection extends E> p)
}
//使用泛型方法
public interface Collection{
void add(Collection p);
void delete(Collection p)
}
也可以同時使用泛型方法和通配符public class Collections{
public static void copy(List dest,List extends T> src){}
}
“菱形”語法與泛型構造器
“菱形”語法前面已經(jīng)提到,不再贅述,說一下啥是泛型構造器,其實就是java允許構造器簽名中聲明泛型形參class Foo{
public Foo(T t){
}
}
public void method(){
//泛型構造器中T類型為String
new Foo("");
//也可以這么定義,顯示指定T類型為String
new Foo("");
//泛型構造器中T類型為Integer
new Foo(10);
}
泛型方法與方法重載
因為泛型既允許設定通配符的上限,也允許設定通配符的下限,從而允許在一個類里包含以下兩種方法的定義 void copy(Collection des,Collection extends T> src){};
T copy(Collection super T> des,Collection src){};
重載的情況public void method(List list){}
public void method(List list){}
上述這段代碼是不能被編譯的,因為參數(shù)List和List編譯之后都被擦除了, 變成了同一種的裸類型List,類型擦除導致這兩個方法的特征簽名變得一模一樣(下面會提到類型擦除)
類型推斷
java 8改進了泛型方法的類型推斷能力,類型推斷主要有如下兩方面
1)可通過調用方法的上下文來推斷泛型的目標類型
2)可在方法調用鏈中,將推斷得到的泛型傳遞到最后一個方法
泛型擦除和轉換
擦除:當把一個具有泛型信息的對象賦給另一個沒有泛型信息的變量時,所有在尖括號之間的類型信息都將被扔掉;Java代碼編譯成Class文件, 然后再用字節(jié)碼反編譯工具進行反編譯后, 將會發(fā)現(xiàn)泛型都不見了, 程序又變回了Java泛型出現(xiàn)之前的寫法, 泛型類型都變回了裸類型(List 對應的裸類型就是List)
比如:List 類型會被轉換成List,則該List對集合元素的類型檢查變成了泛型參數(shù)的上限(Object),那么在使用,比如插入的時候,又會出現(xiàn)從Object到String的強制轉型代碼
擦除法所謂的擦除, 僅僅是對方法的Code屬性中的字節(jié)碼進行擦除, 實際上元數(shù)據(jù)中還是保留了泛型信息, 這也是我們在編碼時能通過反射手段取得參數(shù)化類型的根本依據(jù)
java不支持原生類型的泛型,即是不支持 int/long等,List這種是不支持的,那么一旦把泛型信息擦除后,遇到原生類型時把裝箱、 拆箱也自動做了,這也成為Java泛型慢的重要原因
泛型與數(shù)組
數(shù)組元素的類型不能包含泛型變量或泛型形參,除非是無上限的類型通配符,但可以聲明元素類型包含泛型變量或泛型形參的數(shù)組。也就是說,只能聲明List[]形式的數(shù)組,但不能創(chuàng)建ArrayList[10]這樣的數(shù)組對象
總結
以上是生活随笔為你收集整理的java模型给泛型_【一天一个基础系列】- java之泛型篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 制作支付页面弹框html,JS实现仿微信
- 下一篇: 华为官方强制线刷工具_一加8/8Pro