您好,登錄后才能下訂單哦!
java中泛型Generic的作用是什么?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
泛型技術誕生之前(JDK5以前),創建集合的類型都是Object 類型的元素,存儲內容沒有限制,編譯時正常,運行時容易出現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 中引入泛型,從而可以在編譯時檢測是否存在非法的類型數據結構。
其本質就是參數化類型,可以用于類、接口和方法中,分別被稱為泛型類、泛型接口、泛型方法。
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); } }
定義類時設置泛型,該泛型可用于類中的屬性或方法中,調用該泛型類時,指定具體類型;
// 調用泛型類 public class GenericTest { public static void main(String[] args) { Generic<String> strGen = new Generic<>("a"); String key = strGen.getKey(); System.out.println(key); } } // 定義泛型類 // @param <T> 使用類時指定 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)調用泛型類時未定義類型,則會按照Object 類型處理;
2)調用時分別指定不同類型,但本質都是Object 類型;
3)泛型不支持基本數據類型;
4)泛型類的成員方法不可以用static 修飾(泛型方法可以)。
需求:抽獎活動,但抽獎內容沒有確定,可能都是現金,也可能都是物品
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())); } }
子類也是泛型類,則泛型要保持一致。
class ChildFirst<T> extends Parent{ ... }
1)指定子類泛型,不指定父類泛型,父類默認為Object 類型
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)若父類保留原有泛型,與子類泛型不一致,則會編譯出錯
class ChildFirst<T> extends Parent<E>{ @Override public E getValue() { return super.getValue(); }
3)父類泛型與子類保持一致
具體泛型指定是由子類傳遞到父類當中,所以繼承時父類要與子類泛型保持一致(當然都寫成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)補充:
子類可以進行泛型擴展,但子類必須有一個泛型與父類一致
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(); } }
子類不是泛型類,父類要明確泛型的數據類型
class ChildSecond extends Parent<String>{ ... }
1)子類不是泛型類,不指定父類泛型,父類默認為Object 類型
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)父類要明確泛型的數據類型
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>{ ... }
實現類不是泛型類,接口要明確數據類型
class Apple implements Generator<String>{ @Override public String getKey() { return "Generator interface"; } }
實現類也是泛型類,實現類和接口的泛型類型要一致
class Apple<T> implements Generator<T>{ private T key; @Override public T getKey() { return key; } }
修飾符 <T,E,..> 返回值類型 方法名(形參列表){ } // 泛型方法 public <E,T> E getProduct(ArrayList<E> list) { return list.get(random.nextInt(list.size())); }
修飾符 <T,E,..> 返回值類型 方法名(形參列表){ } // 泛型方法 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)包含泛型列表的方法才是泛型方法,泛型類中使用了泛型的方法并不是泛型方法;
2)泛型列表中聲明了泛型類型,才可以在方法中使用泛型類型;
3)泛型方法中的泛型類型獨立于泛型類的泛型,與類泛型類型無關;
4)泛型方法可以用static 修飾(泛型類的成員方法不可以)。
// 抽獎器 // @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); } }
類型通配符一般用【?】代替具體的類型 實參;
泛型類被調用時,需要指定泛型類型,當泛型類的方法被調用時,不能靈活對應多種泛型類型的需求,如下面代碼【4.】部分所示:
public class BoxTest { public static void main(String[] args) { // 3.調用showBox Box<Number> box1 = new Box<>(); box1.setFirst(100); showBox(box1); // 4.再次調用showBox // 出現問題:類型發生變化后會報錯 Box<Integer> box2 = new Box<>(); box2.setFirst(200); showBox(box2); } // 2. 調用泛型類,此時需要指定泛型類型 public static void showBox(Box<Number> box) { Number first = box.getFirst(); System.out.println(first); } } // 1.定義泛型類 class Box<E>{ private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } }
解決上述問題,類型通配符【?】登場
public class BoxTest { public static void main(String[] args) { // 3.調用showBox Box<Number> box1 = new Box<>(); box1.setFirst(100); showBox(box1); // 4.再次調用showBox // 問題得以解決 Box<Integer> box2 = new Box<>(); box2.setFirst(200); showBox(box2); } // 2. 調用泛型類,此時需要指定泛型類型 // 【?】類型通配符等成 public static void showBox(Box<?> box) { Object first = box.getFirst(); System.out.println(first); } } // 1.定義泛型類 class Box<E>{ private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } }
【6.2】代碼例中,雖然使用了通配符,但 box.getFirst()返回類型仍然需要定義成Object 類型,并不理想。
public static void showBox(Box<?> box) { Object first = box.getFirst(); System.out.println(first); }
通配符上限登場:
調用showBox 方法時,傳遞的泛型類型可以是Number 及其子類(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(); // 此處編譯報錯:類型不一致 // 雖然定義上限,showBox 被調用時沒問題,但在方法內同時定義多種類型,編譯器無法識別 Integer second = box.getFirst(); System.out.println(first); }
public static void showBox(Box<? super Integer> box) { Number first = box.getFirst(); System.out.println(first); }
注意:
遍歷時要用Object 類型進行遍歷;
泛型信息只存在于代碼編譯階段,進入JVM之前,與泛型相關的信息會被擦除,這個行為稱為類型擦除。
Java中的集合主要分為四類:1、List列表:有序的,可重復的;2、Queue隊列:有序,可重復的;3、Set集合:不可重復;4、Map映射:無序,鍵唯一,值不唯一。
關于java中泛型Generic的作用是什么問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。