------------恢復內容開始------------
一、泛型的概念
泛型:即參數化類型,那什么又是參數化類型呢?以前我定義一個屬性或者方法的時候,我們都會明確具體的類型,比如int、String、void等等,但是參數化之后,就不明確類型,只有在具體調用對象的時候,才傳遞實際類型實參,這就叫參數化類型,把類型明確的工作推遲到創建對象或調用方法的時候才去明確的特殊的類型,簡而言之,就是在定義一個對象的時候沒有賦予確切的參數類型,在實例化一個對象的時候傳遞確切的參數,類似於形參和實參的一種情況。
Java泛型設計原則:只要在編譯時期沒有出現警告,那么運行時期就不會出現ClassCastException異常.
Java泛型的設計目的:主要是為了解決當向一個集合輸入不同的數據類型時,輸出讀取時會報錯的問題,例如向一個集合中添加字符串、數字、字符等類型的數據時,當輸出時會報錯誤。
相關術語:
ArrayList<E>
中的E稱為類型參數變量,常用的類型參數符號有K、E、V、MArrayList<Integer>
中的Integer稱為實際類型參數- 整個稱為
ArrayList<E>
泛型類型 - 整個
ArrayList<Integer>
稱為參數化的類型ParameterizedType - 一些常用的泛型類型變量:
E:元素(Element),多用於java集合框架
K:關鍵字(Key)
N:數字(Number)
T:類型(Type)
V:值(Value)
二、為什么需要泛型
早期Java是使用Object來代表任意類型的,但是向下轉型有強轉的問題,這樣程序就不太安全
首先,我們來試想一下:沒有泛型,集合會怎么樣
- 把對象扔進集合中,集合是不知道元素的類型是什么的,僅僅知道是Object。因此在get()的時候,返回的是Object。外邊獲取該對象,還需要強制轉換
- Collection、Map集合對元素的類型是沒有任何限制的。本來我的Collection集合裝載的是全部的Dog對象,但是外邊把Cat對象存儲到集合中,是沒有任何語法錯誤的。
package daily; import java.util.LinkedList; import java.util.List; public class fanxing { public static void main(String[] args) { List li = new LinkedList(); li.add("java編程思想");//向List集合中加入字符串 li.add('愛');//向List集合中加入一個字符 li.add(97);//向List集合中加入整型數據 for (int i=0;i<li.size();i++) { String j = (String) li.get(i);//當然你這里不用強制類型轉換的話,也是能完全打印輸出的,因為它默認為時Object,但是你使用增強for的話,就無法明確具體的類型 System.out.println(j); } } } 運行結果: java編程思想 Exception in thread "main" java.lang.ClassCastException: class java.lang.Character cannot be cast to class java.lang.String //報錯
2.1有了泛型后使用增強foreach遍歷集合
//創建集合對象 ArrayList<String> list = new ArrayList<>(); //明確集合為String類型,則只能往該集合添加字符串元素 list.add("hello"); list.add("world"); list.add("java"); //遍歷,由於明確了類型.我們可以增強for for (String s : list) { System.out.println(s); }
2.1有了泛型后能減少方法的重載
我們編寫代碼的時候,當遇到功能相似的方法的話,就會進行方法的重載,比如計算兩個浮點型的和,計算兩個整型的和,這兩個方法的功能相似,就可以進行方法的重載
但是引入泛型之后,只需要寫入一個方法就可以了,減少該方法的重載。
三、泛型分類
泛型的分類主要分為:泛型類、泛型接口、泛型方法
3.1 泛型類
泛型類就是把泛型定義在類上,用戶使用該類的時候,才把類型明確下來....這樣的話,用戶明確了什么類型,該類就代表着什么類型...用戶在使用的時候就不用擔心強轉的問題,運行時轉換異常的問題了。
3.1.1類的定義:
/* 1:把泛型定義在類上 2:類型變量定義在類上,方法中也可以使用 */ public class ObjectTool<T> { private T obj;//變量的數據類型和泛型類所傳遞的數據類型一致 public T getObj() {//函數的返回類型和泛型類所傳遞的數據類型一致 return obj; } public void setObj(T obj) { this.obj = obj; } }
測試代碼:
public static void main(String[] args) { //創建對象並指定元素類型為字符串類型 ObjectTool<String> tool = new ObjectTool<>(); tool.setObj("一只懶熊"); String s = tool.getObj(); System.out.println(s); //創建對象並指定元素類型為整數類型 ObjectTool<Integer> objectTool = new ObjectTool<>(); /* 如果我在這個對象里傳入的是String類型的,它在編譯時期就通過不了了. */ objectTool.setObj(10); int i = objectTool.getObj(); System.out.println(i); }
3.1.2泛型類的繼承:泛型類是擁有泛型這個特性的類,它本質上還是一個Java類,那么它就可以被繼承
那它是怎么被繼承的呢?這里分兩種情況
- 子類明確泛型類的類型參數變量
- 子類不明確泛型類的類型參數變量
情況1:子類明確泛型類的類型參數變量
//把泛型定義在接口上 public interface Inter<T> { public abstract void show(T t); } //定義一個子類來實現接口 public class InterImpl implements Inter<String> {//子類明確泛型類的類型參數變量為String: @Override public void show(String s) { System.out.println(s); } } //測試代碼 public class mingquefanxingcanshu { public static void main(String[] args) { Inter<String> i = new InterImpl(); i.show("hello java!"); } }
情況2:子類不明確泛型類的類型參數變量
//把泛型定義在接口上 public interface Inter<T> { public abstract void show(T t); } //定義一個子類來實現接口 public class InterImpl<T> implements Inter<T> {//實現類不明確泛型類的類型參數變量,實現類也要定義出<T>類型的 @Override public void show(T s) {//子類方法也要繼承類的數據類型T System.out.println(s); } } //測試代碼 public class mingquefanxingcanshu { public static void main(String[] args) { Inter<String> i = new InterImpl(); i.show("hello java!"); } }
注意:
- 實現類的要是重寫父類的方法,返回值的類型是要和父類一樣的!
- 類上聲明的泛形只對非靜態成員有效
------------恢復內容結束------------