摘要:總結(jié)泛型的類型必須是引用類型,不能是基本類型,泛型的個數(shù)可以有多個,可以使用對創(chuàng)建對象時的泛型類型以及方法參數(shù)類型進(jìn)行限制,如使用關(guān)鍵字和對泛型的具體類型進(jìn)行向下限制或向上限制,最后一點,可以聲明泛型數(shù)組,但是不能創(chuàng)建泛型數(shù)組的實例。
自從 JDK 1.5 提供了泛型概念,泛型使得開發(fā)者可以定義較為安全的類型,不至于強制類型轉(zhuǎn)化時出現(xiàn)類型轉(zhuǎn)化異常,在沒有反省之前,可以通過 Object 來完成不同類型數(shù)據(jù)之間的操作,但是強制類型轉(zhuǎn)換(向下轉(zhuǎn)型)在不確定具體類型的情況下會出錯,泛型機制的引入就是解決數(shù)據(jù)類型不明確 的問題。
定義泛型類定義一個泛型類,語法如下:
//定義泛型類 class 類名{ }
其中,T 表示一個類型的名稱,T 可以表示成其他名稱,一般習(xí)慣寫成 T,<> 里面的類型可以有多個,中間以逗號隔開,下面是一個泛型類,具體如下:
/** * 定義泛型類 * @author jzman * @param*/ public class GenercityClass { private T1 score; private T2 desc; public GenercityClass() {} public GenercityClass(T1 score, T2 desc) { this.score = score; this.desc = desc; } public T1 getScore() { return score; } public void setScore(T1 score) { this.score = score; } public T2 getDesc() { return desc; } public void setDesc(T2 desc) { this.desc = desc; } public static void main(String[] args) { //使用時指定具體類型,具體類型只能是引用類型,不能時基本類型,如 int GenercityClass genercity = new GenercityClass<>(90,"A"); int score = genercity.getScore(); String desc = genercity.getDesc(); System.out.println("score="+score+",desc="+desc); } }
顯然,使用泛型定義的類可以在使用時根據(jù)不同的需求指定
GenercityClass定義泛型接口genercityClass = new GenercityClass<>(); //符合指定的具體類型 genercityClass.setScore(80); //不能將String的值賦值給Integer類型的變量 genercityClass.setScore("A");
定義泛型接口,語法具體如下:
//定義泛型接口 interface 接口名{ 方法返回值類型 方法名 ; }
下面是一個泛型接口的定義,具體如下:
/** * 泛型接口:只能在方法中使用指定泛型 * @author jzman */ public interface GenercityInterface{ //泛型不能在靜態(tài)屬性前面使用 // T a; //方法中使用泛型 void start(T t); }
在接口中使用泛型,只能在接口的方法中使用泛型,不能在接口的屬性上使用泛型,因為 Java 接口中的屬性是用 public static final 修飾的,而泛型所代表的具體類型是在使用時確定的,編譯時還不知道泛型所表示的具體類型。
定義泛型方法定義泛型方法,語法具體如下:
//定義泛型方法 修飾符返回值類型 方法名{ }
創(chuàng)建一個類,具體如下:
package com.manu.genericity; public class PersonBean { private String name; private int age; //省略 Getter、Setter等方法 //... }
下面是一個泛型方法的定義,具體如下:
/** * 泛型方法 * @author jzman */ public class GenercityMethod { public static void main(String[] args) { PersonBean bean = new PersonBean("tom",10); printA("string"); printA(bean); printB(bean); } //泛型不指定其超類,由于類型無法確定,只能訪問其信息 public staticvoid printA(T t) { System.out.println(t); } //泛型指定超類,可以修改其泛型表示的實體信息 public static void printB(T t) { t.setName("haha"); System.out.println(t); } }
輸出結(jié)果如下:
string PersonBean [name=tom, age=10] PersonBean [name=haha, age=10]
由于泛型方法 printA 具體類型不確定,不能修改其泛型信息,printB 指定了其超類,一定程度上可以修改泛型表示的具體類型的信息。泛型可以定義在方法中,是否有泛型方法,與其所在的類是否有泛型沒有關(guān)系。
泛型繼承子類繼承父類的時候,泛型又該如何處理呢,下面的子類繼承帶泛型父類的幾種情況,具體如下:
/** * 泛型父類 * @author jzman */ public abstract class GenercityEClass{ T name; public abstract void print(T t); } /** * 子類為泛型類,類型在使用時確定 * @author jzman * @param */ class Child1 extends GenercityEClass { T t; //子類的屬性由子類決定 @Override public void print(T t) { //父類的屬性隨父類決定 T name = this.name; } } /** * 子類指定具體類型 * @author jzman */ class Child2 extends GenercityEClass { Integer t; //子類的屬性由子類決定 @Override public void print(String t) { //父類的屬性隨父類決定 String name = this.name; } } /** * 父類泛型的擦除 * 子類是泛型類,父類不指定類型,泛型擦除是使用Object來代替 * @author jzman * @param */ class Child3 extends GenercityEClass{ T t; String t1; //子類的屬性由子類決定 @Override public void print(Object t) { //父類的屬性隨父類決定 Object obj = this.name; } } /** * 子類和父類同時泛型擦除 * @author jzman */ class Child4 extends GenercityEClass{ //只能使用具體類型 String str; //子類的屬性由子類決定 @Override public void print(Object t) { //父類的屬性隨父類決定 Object obj = this.name; } }
可以得到一些結(jié)論:父類中的屬性隨父類而定,子類中的屬性隨子類而定,子類繼承父類時的方法重寫,其相關(guān)的類型隨父類而定,這種帶有泛型的操作在繼承時涉及到泛型擦除,將在下文中說明。
泛型擦除在泛型繼承小節(jié)中涉及到泛型的擦除,感覺比較重要,故多帶帶記錄一下,泛型擦除兩種情況,具體如下:
繼承或?qū)崿F(xiàn)(接口)時泛型擦除;
具體使用時的泛型擦除。
子類繼承父類時,泛型的擦除有兩種情況,具體如下:
子類泛型,父類泛型擦除
子類和父類同時泛型擦除
下面是部分代碼,具體如下:
/** * 父類泛型的擦除 * 子類是泛型類,父類不指定類型,泛型擦除是使用Object來代替 * @author jzman * @param*/ class Child3 extends GenercityEClass{ T t; String t1; //子類的屬性由子類決定 @Override public void print(Object t) { //父類的屬性隨父類決定 Object obj = this.name; } } /** * 子類和父類同時泛型擦除 * @author jzman */ class Child4 extends GenercityEClass{ //只能使用具體類型 String str; //子類的屬性由子類決定 @Override public void print(Object t) { //父類的屬性隨父類決定 Object obj = this.name; } } /** * 子類擦除,父類使用泛型(錯誤) * @author jzman * class Child5 extends GenercityEClass { @Override public void print(T t) { } } */
注意一點,不能父類泛型,子類泛型擦除,只能子類泛型在大于等于父類泛型個數(shù)的情況下才能進(jìn)行泛型擦除。類實現(xiàn)泛型接口與類之間的繼承類似,不再贅述。
下面是具體使用時的泛型擦除,具體如下:
class Child1extends GenercityEClass { T t; //子類的屬性由子類決定 @Override public void print(T t) { //父類的屬性隨父類決定 T name = this.name; } public static void main(String[] args) { //1.使用時泛型擦除 Child1 child1 = new Child1(); Object obj = child1.name;//屬性name為擦除后的類型Object //2.使用時指定類型 Child1 child2 = new Child1(); String name = child2.name;//屬性name為指定的類型 String } }
關(guān)于泛型擦除就聊到這。
泛型的高級用法泛型的高級用法具體如下:
限制泛型可用類型
使用類型通配字符
默認(rèn)可以使用任何類型來實例化一個泛型類對象,也可以對泛型類實例的類型進(jìn)行限制,語法具體如下:
//限制泛型可用類型 class{ }
上面的 AnyClass 可以是一個類也可以是一個接口,也就是說泛型的類型必須繼承 AnyClass 類或?qū)崿F(xiàn) AnyClass 接口,無論是類還是接口,進(jìn)行類型限制時都是用 extends 關(guān)鍵字。下面是案例,具體如下:
/** * 泛型可用類型限制 * @author jzman */ public class LimitGenercityClass{ public static void main(String[] args) { // T extends:<上限,T可以是上限的子類或其本身 LimitGenercityClass > limitClass1 = new LimitGenercityClass<>(); LimitGenercityClass > limitClass2 = new LimitGenercityClass<>(); //HashMap沒有實現(xiàn)List接口,故HashMap不能對泛型類實例的類型實例化 // LimitGenercityClass > limitClass3 = new LimitGenercityClass<>(); } }
上述代碼中對泛型 T 進(jìn)行了限制,具體的泛型類型必須實現(xiàn) List 接口,ArrayList 和 LinkedList 實現(xiàn)了 List 接口,而 HashMap 沒有實現(xiàn) List 接口,所以 HashMap 不能實例化對應(yīng)泛型的具體類型。
在泛型機制中提供了類型通配符,主要作用是創(chuàng)建一個泛型類對象時限制這個泛型類的類型繼承或?qū)崿F(xiàn)某個類或接口,可以使用 ? 通配符來實現(xiàn),同時也可以使用 extends、super 關(guān)鍵字對泛型進(jìn)行限制,使用類型通配符語法具體如下:
//使用類型通配符 泛型類名稱 extends AnyClass> a ;
下面是類型通配符的使用,具體如下:
/** * 使用通配符 * ? extends AnyClass:限制泛型的具體類型只能是AnyClass的子類 * ? super AnyClass:限制泛型的具體類型只能是AnyClass的超類 * @author jzman */ public class CommonCharGenercityClass{ public static void main(String[] args) { //1.通配符用在類型聲明上 CommonCharGenercityClass extends List> commA = null; //通配符中使用extends關(guān)鍵字限制了泛型只能是List的子類 commA = new CommonCharGenercityClass >(); commA = new CommonCharGenercityClass >(); // commA = new CommonCharGenercityClass >(); CommonCharGenercityClass super List> commB = null; //出錯,通配符中使用super關(guān)鍵字限制了泛型只能是 List 的超類才可以,比如Object // commB = new CommonCharGenercityClass >(); commB = new CommonCharGenercityClass
類型通配符 ? 可以結(jié)合關(guān)鍵字 extends 和 super 來實現(xiàn)對泛型具體類型的限制,extends 限制泛型的具體類型應(yīng)該是目標(biāo)類型的子類,super 限制泛型的具體類型應(yīng)該是目標(biāo)類型的超類,此外,類型通配符不能用在聲明類上。
泛型作用編譯的時候檢查類型安全,提前發(fā)現(xiàn)錯誤
泛型中的類型強制轉(zhuǎn)換都是自動和隱式的,提高了代碼的重用率。
總結(jié):泛型的類型必須是引用類型,不能是基本類型,泛型的個數(shù)可以有多個,可以使用 ?對創(chuàng)建對象時的泛型類型以及方法參數(shù)類型進(jìn)行限制,如使用關(guān)鍵字 extends 和 super 對泛型的具體類型進(jìn)行向下限制或向上限制,最后一點,可以聲明泛型數(shù)組,但是不能創(chuàng)建泛型數(shù)組的實例。
可以選擇關(guān)注微信公眾號:jzman-blog 獲取最新更新,一起交流學(xué)習(xí)!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74886.html
摘要:簡述大家在平時的工作學(xué)習(xí)中肯定會見過不少如下的語句我們都知道上面的代碼時關(guān)于泛型的那么這兩個不同的寫法都有什么區(qū)別呢首先說到的泛型我們必須要提到的是泛型的類型擦除機制中的泛型基本上都是在編譯器這個層次來實現(xiàn)的在生成的字節(jié)代碼中是不包含泛型中 簡述 大家在平時的工作學(xué)習(xí)中, 肯定會見過不少如下的語句: List 就表示了泛型參數(shù)是某個類型, 只不過我們并不知道它的具體類型時什么.List...
摘要:當(dāng)活動線程核心線程非核心線程達(dá)到這個數(shù)值后,后續(xù)任務(wù)將會根據(jù)來進(jìn)行拒絕策略處理。線程池工作原則當(dāng)線程池中線程數(shù)量小于則創(chuàng)建線程,并處理請求。當(dāng)線程池中的數(shù)量等于最大線程數(shù)時默默丟棄不能執(zhí)行的新加任務(wù),不報任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點記錄以及采用的解決方案 深入分析 java 線程池的實現(xiàn)原理 在這篇文章中,作者有條不紊的將 ja...
閱讀 1048·2021-11-22 13:53
閱讀 1598·2021-11-17 09:33
閱讀 2400·2021-10-14 09:43
閱讀 2862·2021-09-01 11:41
閱讀 2279·2021-09-01 10:44
閱讀 2920·2021-08-31 09:39
閱讀 1457·2019-08-30 15:44
閱讀 1866·2019-08-30 13:02