Java中泛型的介紹和使用
- 2019 年 12 月 2 日
- 筆記
!今天主要給大家說下Java中泛型的使用以及泛型是什麼?下面請看正文
- 泛型概述
我們都知道Java里的集合(list,map….)是可以存放任意對象的,只要把對象存儲集合後,那麼這時他們都會被提升成Object類型。當我們在取出每一個對象,並且進行相應的操作,這時必須採用類型轉換。看下面這段示例程式碼
package com.mobaijun; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class GeneriDemo1{ public static void main(String[] args) { Collection coll = new ArrayList(); coll.add("mobai"); coll.add("墨白"); coll.add(5);//由於集合沒有做任何限定,任何類型都可以給其中存放 Iterator it = coll.iterator(); while (it.hasNext()) { //需要列印每個字元串的長度,就要把迭代出來的對象轉成String類型 String str = (String) it.next(); System.out.println(str.length()); } } }
我們可以看到控制台列印結果是一個異常,異資訊如下:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
這個Demo在運行時發生了java.lang.ClassCastException,找不到主類或無法載入類。為什麼會發生類型轉換異常呢?我們來分析下:由於集合中什麼類型的元素都可以存儲。導致取出時強轉引發運行時 ClassCastException。怎麼來解決這個問題呢?
Collection雖然可以存儲各種對象,但實際上通常Collection只存儲同一類型對象。例如都是存儲字元串對象。因此 在JDK5之後,新增了泛型(Generic)語法,讓你在設計API時可以指定類或方法支援泛型,這樣的話我們使用API的時候 也變得更為簡潔,並得到了編譯時期的語法檢查。
一句話概述就是:泛型可以在類或方法中預支地使用未知的類型
- 那麼使用泛型有什麼好處呢?
看下面程式碼體驗一下泛型帶給我們的好處:
package com.mobaijun; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class GeneriDemo2 { public static void main(String[] args) { Collection<String> list = new ArrayList<String>(); list.add("mobai"); list.add("墨白"); // list.add(5); // 當集合明確類型後,存放類型不一致就會編譯報錯 // 集合已經明確具體存放的元素類型,那麼在使用迭代器的時候,迭代器也同樣會知道具體遍曆元素類型 Iterator<String> it = list.iterator(); while (it.hasNext()) { String str = it.next(); //當使用Iterator<String>控制元素類型後,就不需要強轉了。獲取到的元素直接就是String類 型 System.out.println(str.length()); } } }
- 泛型的定義與使用
泛型,用來靈活地將數據類型應用到不同的類、方法、介面當中。將數據類型作為參數進行傳遞。
泛型的定義格式:
修飾符 class 類名<代表泛型的變數> { }
示例程式碼:
class ArrayList<E> { public boolean add(E e) { } public E get(int index) { } }
泛型在定義的時候不具體,使用的時候才變得具體。在使用的時候確定泛型的具體數據類型。
使用泛型:即什麼時候確定泛型。
在創建對象的時候確定泛型
例如, ArrayList<String> list = new ArrayList<String>();
此時,變數E的值就是String類型,那麼我們的類型就可以理解為
class ArrayList<String> { public boolean add(String e) { } public String get(int index) { } }
再例如, ArrayList<Integer> list = new ArrayList<Integer>();
此時,變數E的值就是Integer類型,那麼我們的類型就可以理解為:
class ArrayList<Integer> { public boolean add(Integer e) { } public Integer get(int index) { } }
- 泛型方法
示例程式碼:
public class MyGenericMethod { public <MVP> void show(MVP mvp) { System.out.println(mvp.getClass()); } public <MVP> MVP show2(MVP mvp) { return mvp; } }
在方法調用的時候,明確泛型的類型:程式碼如下
package com.mobaijun; public class GeneriDemo3 { public static void main(String[] args) { MyGenericMethod my = new MyGenericMethod(); my.show("墨白"); my.show(18); my.show(178.0); } }
- 泛型的介面
示例程式碼:
package com.mobaijun; public interface MyGenericInterface<E> { public abstract void add(E e); public abstract E gitE(); }
下面我們來看下如果要定義一個類該如何使用泛型:
示例程式碼:
package com.mobaijun; public class MyImpl implements MyGenericInterface<String>{ @Override public void add(String s) { // 省略 } @Override public String gitE() { return null; } }
在類開始的時候我們以及定義了泛型的類型,那麼這個時候泛型e的值就是String;
- 如果始終不確定泛型的類型,可以直到創建對象時,確定泛型的類型
package com.mobaijun; /** * 不確定泛型的類型 * @param <E> */ public class MyImpl2<E> implements MyGenericInterface<E> { @Override public void add(E e) { } @Override public E gitE() { return null; } }
- 在創建對象的時候確定泛型的類型
package com.mobaijun; /** * 創建對象的時候確定泛型的類型 */ public class GenericInterface { public static void main(String[] args) { MyImpl2<String> my = new MyImpl2<String>(); my.add("墨白"); } }
- 泛型還有最後一個知識點,那就是泛型的通配符
當使用泛型類或者介面時,傳遞的數據中,泛型類型不確定,可以通過通配符<?>表示。但是一旦使用泛型的通配符後,只能使用Object類中的共性方法,集合中元素自身方法無法使用。
通配符的基本使用 有如下幾點
泛型的通配符:不知道使用什麼類型來接收的時候,此時可以使用?,?表示未知通配符。
此時只能接受數據,不能往該集合中存儲數據。
示例程式碼:
package com.mobaijun; import java.util.ArrayList; import java.util.Collection; public class MyDemo { public static void main(String[] args) { Collection<Integer> c = new ArrayList<Integer>(); getElement(c); Collection<String> c2 = new ArrayList<String>(); getElement(c2); } /** * 統配符中的?代表著任意類型數據 * 需要注意的是泛型是不存在繼承關係的, * Collection<Object> c2 = new ArrayList<String>();錯誤示例 * @param collection */ public static void getElement(Collection<?> collection){ } }
- 通配符高級使用
之前設置泛型的時候,實際上是可以任意設置的,只要是類就可以設置。但是在JAVA的泛型中可以指定一個泛型的上限和下限。
泛型的上限:
格式:類型名稱 <? extends 類 > 對象名稱 意義:只能接收該類型及其子類
泛型的下限:
格式:類型名稱 <? super 類 > 對象名稱 意義:只能接收該類型及其父類型
舉個例子,比如:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類
package com.mobaijun; import java.util.ArrayList; import java.util.Collection; public class MyDemo4 { public static void main(String[] args) { Collection<Integer> c1 = new ArrayList<Integer>(); Collection<String> c2 = new ArrayList<String>(); Collection<Number> c3 = new ArrayList<Number>(); Collection<Object> c4 = new ArrayList<Object>(); getElementOne(c1); getElementOne(c2);// 編譯報錯 getElementOne(c3); getElementOne(c4);// 編譯報錯 getElementTow(c1);// 編譯報錯 getElementTow(c2);// 編譯報錯 getElementTow(c3); getElementTow(c4); } // 泛型的上限:此時的泛型?,必須是Number類型或者Number類型的子類 public static void getElementOne(Collection<? extends Number> collection){} // 泛型的下限:此時的泛型?,必須是Number類型或者Number類型的父類 public static void getElementTow(Collection<? super Number> collection){} }
以上就是泛型的全部內容了,如果有幫助到你,請在文末點個在看,祝你有個美好的一天,加油!!!