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