- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- 深入理解java泛型Generic
泛型技術(shù)誕生之前(JDK5以前),創(chuàng )建集合的類(lèi)型都是Object 類(lèi)型的元素,存儲內容沒(méi)有限制,編譯時(shí)正常,運行時(shí)容易出現ClassCastException 異常。
public class Test { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("java"); list.add(100); list.add(true); for(int i = 0;i <list.size();i++) { Object o = list.get(i); String str = (String)o; System.out.println(str); } } }
輸出:
java
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.chengyu.junit.Test.main(Test.java:18)
JDK5 中引入泛型,從而可以在編譯時(shí)檢測是否存在非法的類(lèi)型數據結構。
其本質(zhì)就是參數化類(lèi)型,可以用于類(lèi)、接口和方法中,分別被稱(chēng)為泛型類(lèi)、泛型接口、泛型方法。
public static void main(String[] args) { ArrayList<String> strList = new ArrayList<String>(); strList.add("java"); strList.add("C#"); for(int i = 0;i < strList.size();i++) { String str = strList.get(i); System.out.println(str); } }
定義類(lèi)時(shí)設置泛型,該泛型可用于類(lèi)中的屬性或方法中,調用該泛型類(lèi)時(shí),指定具體類(lèi)型;
// 調用泛型類(lèi) public class GenericTest { public static void main(String[] args) { Generic<String> strGen = new Generic<>("a"); String key = strGen.getKey(); System.out.println(key); } } // 定義泛型類(lèi) // @param <T> 使用類(lèi)時(shí)指定 class Generic<T>{ private T key; public Generic(T key) { this.key = key; } public T getKey() { return key; } public void setKey(T key) { this.key = key; } @Override public String toString() { return "GenericTest [key=" + key + "]"; } }
1)調用泛型類(lèi)時(shí)未定義類(lèi)型,則會(huì )按照Object 類(lèi)型處理;
2)調用時(shí)分別指定不同類(lèi)型,但本質(zhì)都是Object 類(lèi)型;
3)泛型不支持基本數據類(lèi)型;
4)泛型類(lèi)的成員方法不可以用static 修飾(泛型方法可以)。
需求:抽獎活動(dòng),但抽獎內容沒(méi)有確定,可能都是現金,也可能都是物品
public class ProductGetterTest { public static void main(String[] args) { // 抽物品 ProductGetter<String> strProductGetter = new ProductGetter<>(); String[] str = {"手機","電視","洗衣機"}; for(int i = 0; i < str.length; i ++ ) { strProductGetter.addProduct(str[i]); } String strProduct = strProductGetter.getProduct(); System.out.println("恭喜您抽中了" + strProduct); System.out.println("============================================="); // 抽現金 ProductGetter<Integer> intProductGetter = new ProductGetter<>(); Integer[] integer = {1000,2000,3000}; for(int i = 0; i < integer.length; i ++ ) { intProductGetter.addProduct(integer[i]); } int intProduct = intProductGetter.getProduct(); System.out.println("恭喜您抽中了" + intProduct); } } // 抽獎器 class ProductGetter<T>{ Random random = new Random(); // 獎品池 ArrayList<T> list = new ArrayList<>(); // 添加獎品 public void addProduct(T t) { list.add(t); } // 抽獎(獲取獎品) public T getProduct() { return list.get(random.nextInt(list.size())); } }
子類(lèi)也是泛型類(lèi),則泛型要保持一致。
class ChildFirst<T> extends Parent{ ... }
1)指定子類(lèi)泛型,不指定父類(lèi)泛型,父類(lèi)默認為Object 類(lèi)型
class Parent<E>{ private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst<T> extends Parent{ @Override public Object getValue() { return super.getValue(); } }
2)若父類(lèi)保留原有泛型,與子類(lèi)泛型不一致,則會(huì )編譯出錯
class ChildFirst<T> extends Parent<E>{ @Override public E getValue() { return super.getValue(); }
3)父類(lèi)泛型與子類(lèi)保持一致
具體泛型指定是由子類(lèi)傳遞到父類(lèi)當中,所以繼承時(shí)父類(lèi)要與子類(lèi)泛型保持一致(當然都寫(xiě)成E也可以)。
class Parent<E>{ private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst<T> extends Parent<T>{ @Override public T getValue() { return super.getValue(); } }
4)調用
public class GenericTest { public static void main(String[] args) { ChildFirst<String> childFirst = new ChildFirst<>(); childFirst.setValue("chengyu"); System.out.println(childFirst.getValue()); } }
5)補充:
子類(lèi)可以進(jìn)行泛型擴展,但子類(lèi)必須有一個(gè)泛型與父類(lèi)一致
public class GenericTest { public static void main(String[] args) { ChildFirst<String,Integer> childFirst = new ChildFirst<>(); childFirst.setValue("chengyu"); System.out.println(childFirst.getValue()); } } class Parent<E>{ private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst<T,E> extends Parent<T>{ @Override public T getValue() { return super.getValue(); } }
子類(lèi)不是泛型類(lèi),父類(lèi)要明確泛型的數據類(lèi)型
class ChildSecond extends Parent<String>{ ... }
1)子類(lèi)不是泛型類(lèi),不指定父類(lèi)泛型,父類(lèi)默認為Object 類(lèi)型
class Parent<E>{ private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildSecond extends Parent{ @Override public Object getValue() { return super.getValue(); } }
2)父類(lèi)要明確泛型的數據類(lèi)型
class ChildSecond extends Parent<String>{ @Override public String getValue() { return super.getValue(); } }
3)調用
public class GenericTest { public static void main(String[] args) { ChildSecond childSecond = new ChildSecond(); childSecond.setValue("chengyu2"); System.out.println(childSecond.getValue()); } }
public interface Generator<T>{ ... }
實(shí)現類(lèi)不是泛型類(lèi),接口要明確數據類(lèi)型
class Apple implements Generator<String>{ @Override public String getKey() { return "Generator interface"; } }
實(shí)現類(lèi)也是泛型類(lèi),實(shí)現類(lèi)和接口的泛型類(lèi)型要一致
class Apple<T> implements Generator<T>{ private T key; @Override public T getKey() { return key; } }
修飾符 <T,E,..> 返回值類(lèi)型 方法名(形參列表){ } // 泛型方法 public <E,T> E getProduct(ArrayList<E> list) { return list.get(random.nextInt(list.size())); }
修飾符 <T,E,..> 返回值類(lèi)型 方法名(形參列表){ } // 泛型方法 public <E,T> E getProduct(ArrayList<E> list) { return list.get(random.nextInt(list.size())); }
public <E> void print(E... e) { for(int i = 0; i < e.length;i++){ System.out.println(e[i]); } } // 調用 print(1,2,3,4);
1)包含泛型列表的方法才是泛型方法,泛型類(lèi)中使用了泛型的方法并不是泛型方法;
2)泛型列表中聲明了泛型類(lèi)型,才可以在方法中使用泛型類(lèi)型;
3)泛型方法中的泛型類(lèi)型獨立于泛型類(lèi)的泛型,與類(lèi)泛型類(lèi)型無(wú)關(guān);
4)泛型方法可以用static 修飾(泛型類(lèi)的成員方法不可以)。
// 抽獎器 // @param <t> class ProductGetter<T>{ Random random = new Random(); // 獎品池 ArrayList<T> list = new ArrayList<>(); // 添加獎品 public void addProduct(T t) { list.add(t); } // 抽獎(獲取獎品) public T getProduct() { return list.get(random.nextInt(list.size())); } // 泛型方法 public <E> E getProduct(ArrayList<E> list) { return list.get(random.nextInt(list.size())); } }
public class ProductGetterTest { public static void main(String[] args) { ProductGetter<Integer> intProductGetter = new ProductGetter<>(); ArrayList<String> strList = new ArrayList<>(); strList.add("手機"); strList.add("電視"); strList.add("洗衣機"); String product = intProductGetter.getProduct(strList); System.out.println("恭喜您抽中了" + product); } }
類(lèi)型通配符一般用【?】代替具體的類(lèi)型 實(shí)參;
泛型類(lèi)被調用時(shí),需要指定泛型類(lèi)型,當泛型類(lèi)的方法被調用時(shí),不能靈活對應多種泛型類(lèi)型的需求,如下面代碼部分所示:
public class BoxTest { public static void main(String[] args) { // 3.調用showBox Box<Number> box1 = new Box<>(); box1.setFirst(100); showBox(box1); // 4.再次調用showBox // 出現問(wèn)題:類(lèi)型發(fā)生變化后會(huì )報錯 Box<Integer> box2 = new Box<>(); box2.setFirst(200); showBox(box2); } // 2. 調用泛型類(lèi),此時(shí)需要指定泛型類(lèi)型 public static void showBox(Box<Number> box) { Number first = box.getFirst(); System.out.println(first); } } // 1.定義泛型類(lèi) class Box<E>{ private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } }
解決上述問(wèn)題,類(lèi)型通配符【?】登場(chǎng)
public class BoxTest { public static void main(String[] args) { // 3.調用showBox Box<Number> box1 = new Box<>(); box1.setFirst(100); showBox(box1); // 4.再次調用showBox // 問(wèn)題得以解決 Box<Integer> box2 = new Box<>(); box2.setFirst(200); showBox(box2); } // 2. 調用泛型類(lèi),此時(shí)需要指定泛型類(lèi)型 // 【?】類(lèi)型通配符等成 public static void showBox(Box<?> box) { Object first = box.getFirst(); System.out.println(first); } } // 1.定義泛型類(lèi) class Box<E>{ private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } }
【6.2】代碼例中,雖然使用了通配符,但 box.getFirst()返回類(lèi)型仍然需要定義成Object 類(lèi)型,并不理想。
public static void showBox(Box<?> box) { Object first = box.getFirst(); System.out.println(first); }
通配符上限登場(chǎng):
調用showBox 方法時(shí),傳遞的泛型類(lèi)型可以是Number 及其子類(lèi)(Integer)
public static void showBox(Box<? extends Number> box) { Number first = box.getFirst(); System.out.println(first); }
注意:
public static void showBox(Box<? extends Number> box) { Number first = box.getFirst(); // 此處編譯報錯:類(lèi)型不一致 // 雖然定義上限,showBox 被調用時(shí)沒(méi)問(wèn)題,但在方法內同時(shí)定義多種類(lèi)型,編譯器無(wú)法識別 Integer second = box.getFirst(); System.out.println(first); }
public static void showBox(Box<? super Integer> box) { Number first = box.getFirst(); System.out.println(first); }
注意:
遍歷時(shí)要用Object 類(lèi)型進(jìn)行遍歷;
泛型信息只存在于代碼編譯階段,進(jìn)入JVM之前,與泛型相關(guān)的信息會(huì )被擦除,這個(gè)行為稱(chēng)為類(lèi)型擦除。
到此這篇關(guān)于深入理解java泛型Generic的文章就介紹到這了,更多相關(guān)java泛型內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站