目錄
一. 包裝類
1.1 基本數據類型和對應的包裝類
1.2 裝箱和拆箱
?二. 泛型
2.1什么是泛型
2.2泛型的引入
?2.3 泛型類語法?
?2.4 泛型類的使用
?2.5?裸類型(Raw Type)(了解)
?2.6 泛型是如何編譯的?
2.7 泛型的上界
2.8 泛型方法?
一. 包裝類
1.1 基本數據類型和對應的包裝類
包裝類在之前我們就使用過, 使我們寫代碼更加的方便?
1.2 裝箱和拆箱
裝箱(裝包): 把一個基本數據類型轉變為包裝類型
拆箱(拆包): 把一個包裝類型轉變為基本數據類型
int i = 10 ;Integer ii = i ; // 自動裝箱Integer ii = Integer . valueOf ( i ); //顯示裝箱 ---類名.valueOf 說明該方法時用static修飾的Integer jj = new Integer(10) ;int j = jj ; // 自動拆箱int j = jj . intValue (); //顯示拆箱
注:拆箱時, 我們可以將數據拆成我們想要的類型?
Integer jj = new Integer(10);
double d = jj.doubleValue();//拆成double類型
System.out.println(d);
//輸出結果
10.0
?下面看一道面試題:
思考 : 為什么上述代碼只是將100改成200, 輸出的結果卻不同呢?? ?
上述我們唯一做的動作就是裝箱, 那么裝箱時, 調用的方法是Integer.valueOf(), 按住Ctrl點進去查看valueOf的源碼, 我們發現:
?我們傳入的參數, 如果在一個low和high之間, 那么就返回一個數組某下標的值, 如果不在這個范圍內, 那么就new一個對象, 此時即使傳入一樣的參數, 返回的值肯定是不同的.? 那么我們猜測, 200就不在low和high之間, 而100在low和high之間.?
那么我們點進去low和high的源碼, 發現low = -128 , high = 127, 我們的猜測是正確的, 那么cache數組是怎么回事呢?
我們計算一下這個數組:
?二. 泛型
2.1什么是泛型
一般的類和方法,只能使用具體的類型 : 要么是基本類型,要么是自定義的類。如果要編寫可以應用于多種類型的代碼,這種刻板的限制對代碼的束縛就會很大。----- 來源《 Java 編程思想》對泛型的介紹。
2.2泛型的引入
代碼示例:

?①?MyArray<T>? -----??類名后的 <T> 代表占位符,表示當前類是一個泛型類
了解: 【規范】類型形參一般使用一個大寫字母表示,常用的名稱有:E 表示 ElementK 表示 KeyV 表示 ValueN 表示 NumberT 表示 TypeS, U, V 等等 - 第二、第三、第四個類型
②T[] array = (T[])new Object[10] ----??創建泛型類數組
T[] array = (T[])new Object[10], 并不是一個最好的寫法, 最好的寫法是:
Object[] array = new Object[10];
不能new泛型類型的數組?T [] ts = new T [ 5 ]; // 是不對的
③ MyArray<Integer> myArray = new MyArray<>()? -----? ?創建泛型類對象,?類型后加入 <Integer> 指定當前類型?后面的<>中的內容可以省略
④??myArray.setVal(2,"bit")? -----? ?代碼編譯報錯,此時因為在③處指定類當前的類型,此時編譯器會在存放元素的時候幫助我們進行類型檢查。
泛型, 是編譯時期的機制, 在運行時, 沒有泛型的概念
注:<>中的內容不能是基本數據類型, 只能是引用類型/包裝類
想要存放String類型的數據:
?2.3 泛型類語法?
class 泛型類名稱 < 類型形參列表 > {????????// 這里可以使用類型參數}class ClassName < T1 , T2 , ..., Tn > {}class 泛型類名稱 < 類型形參列表 > extends 繼承類 /* 這里可以使用類型參數 */ {????????// 這里可以使用類型參數}class ClassName < T1 , T2 , ..., Tn > extends ParentClass < T1 > {????????// 可以只使用部分類型參數}
?2.4 泛型類的使用
泛型類 < 類型實參 > 變量名 ; // 定義一個泛型類引用new 泛型類 < 類型實參 > ( 構造方法實參 ); // 實例化一個泛型類對象MyArray < Integer > list = new MyArray < Integer > ();//當編譯器可以根據上下文推導出類型實參時,可以省略類型實參的填寫MyArray < Integer > list = new MyArray <> (); // 可以推導出實例化需要的類型實參為 Integer
?2.5?裸類型(Raw Type)(了解)
裸類型是一個泛型類但沒有帶著類型實參,例如 MyArrayList 就是一個裸類型
MyArray list = new MyArray(); ?
?2.6 泛型是如何編譯的?

2.7 泛型的上界
?在定義泛型類時,有時需要對傳入的類型變量做一定的約束,可以通過類型邊界來約束。
語法:
class 泛型類名稱 < 類型形參 extends 類型邊界 > {...}
例:
public class MyArray < E extends Number > {...}
表示: 只接受 Number 或 Number的子類型 作為 E 的類型實參?
MyArray < Integer > l1 ; // 正常,因為 Integer 是 Number 的子類型MyArray < String > l2 ; // 編譯錯誤,因為 String 不是 Number 的子類型
了解:
1.? 沒有指定類型邊界 E,可以視為 E extends Object ?
2. 泛型沒有下界
例: 寫一個泛型類, 求一個數組中的最大值
?顯然這樣是錯誤的, 因為擦除機制將T替換成Object類, 而引用類型是不能直接比較大小的, 需要使用compareTo方法, 并實現Comparable接口,? 我們點進去Object的源碼看發現:?
Object類并沒有實現Comparable接口?
正確的寫法應該是:
意味著, 傳入的參數必須是繼承了Comparable接口的類, 那么Integer我們點進去查看:
?Integer是繼承了Comparable接口的.?
如果我們重新定義一個類當參數:
是不被允許的, 因為沒有Person沒有實現Comparable接口
正確寫法:
2.8 泛型方法?
語法:
方法限定符 < 類型形參列表 > 返回值類型 方法名稱 ( 形參列表 ) { ... }
上述代碼可以寫成 泛型方法:
?
當這個泛型方法是靜態的時,??我們就不用實例化對象, 直接通過類來調用泛型方法?