Java 深入淺出講解泛型與包裝類
1、什么是泛型
泛型的本質是為了參數(shù)化類型(在不創(chuàng)建新的類型的情況下,通過泛型指定的不同類型來控制形參具體限制的類型)。
先看以下的例子:
我們以前學過的數(shù)組,只能存放指定類型的元素。如:int[] array=new int[10];String[] array=new String[10];而Object類是所有類的父類,那么我們是否可以創(chuàng)建Obj數(shù)組呢?
class Myarray{
public Object[] array=new Object[10];
public void setVal(int pos,Object val){
this.array[pos]=val;
}
public Object getPos(int pos){
return this.array[pos];
}
}
public class TestDemo{
public static void main(String[] args) {
Myarray myarray=new Myarray();
myarray.setVal(1,0);
myarray.setVal(2,"shduie");//字符串也可以存放
String ret=(String)myarray.getPos(2);//雖然我們知道它是字符串類型,但是還是要強制類型轉換
System.out.println(ret);
}
}以上代碼實現(xiàn)后,我們發(fā)現(xiàn):
- 任何類型的數(shù)據(jù)都能存放
- 2號下標本來就是字符串,但是必須進行強制類型轉換
以此引出泛型,泛型的目的就是:指定當前的容器要持有什么類型的對象,讓編譯器自己去檢查。
2、泛型的語法
class 泛型類名稱< 類型形參列表>{
//這里可以使用類型參數(shù)
}
泛型的使用:
泛型類<類型實參> 變量名=new 泛型類<類型實參>(構造方法實參)
MyArray list=new MyArray<>();
【注】
- 類型后的<>代表占位符,表示當前類是一個泛型類
- 在實例化泛型時,<>中不能是簡單的類型,需要是包裝類
- <>不參與泛型的類型組成
- 不能new泛型類型的數(shù)組
- 使用泛型不需要進行強制類型轉換
一個簡單的泛型:
//此處T可以隨便寫為任意標識,常見的如T、E、K、V等形式的參數(shù)常用于表示泛型
//在實例化泛型類時,必須指定T的具體類型
public class Test<T>{
//key這個成員變量的類型為T,T的類型由外部指定
private T key;
public Test(T key) { //泛型構造方法形參key的類型也為T,T的類型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值類型為T,T的類型由外部指定
return key;
}
}擦除機制:編譯時會將<>中的類型擦除掉,所以<>中的東西不參與類型的組成。會將T擦除為Object。
為什么不能實例化泛型類型的數(shù)組?
數(shù)組和泛型之間的一個重要區(qū)別是它們如何強制執(zhí)行類型檢查。數(shù)組在運行時存儲和檢查類型信息,而泛型是在編譯時檢查類型錯誤。
返回的Object數(shù)組里面,可能存放著任何類型的數(shù)據(jù),如string,通過int類型的數(shù)組來接收,編譯器認為是不安全的。
3、泛型的上界
語法:
class 泛型類名稱<T extends 類型邊界>{
}
例:
public class MyArray{} //E只能是Number或Number的子類
public class MyArray<E extends Comparable<E>>{}
//E一定實現(xiàn)了Comparable接口的類
【注】沒有指定邊界的E,可以看作 E extends Object
4、通配符
? 用于在泛型的使用,即為通配符。通配符用來解決反泛型無法協(xié)變的問題。
如下兩段代碼:
代碼一:
public static<T> void printList1(ArrayList<T> list){
for(T x:list){
System.out.println(x);
}
}
代碼二:
public static<T> void printList2(ArrayList<?> list){
for(Object x:list){
System.out.println(x);
}
}代碼2中使用了通配符,和代碼1相比,此時傳入代碼1的具體是什么數(shù)據(jù)類型,我們是不清楚的。
(1)通配符的上界
語法:
<? extends 上界>
<? extends Number>//可以傳入的實參類型為Number或Number的子類
例:對于以下關系,我們需要寫一個方法來打印存儲了Animal或者Animal子類的list。
Animal
Cat extends Animal
Dog extends Animal
代碼一:
public static <t extends Animal> void print1(List<T> list>{
for(T animal:list){
System.out.println(animal);//調用了T的toString
}
}此時T類型是Animal的子類或自己。
代碼二:通過通配符實現(xiàn)
public static void print2(List<? extends Animal> list){
for(Animal animal:list){
Syatem.out.println(animal);//調用了子類的toString方法
}
}兩種代碼的區(qū)別:
- 對于泛型實現(xiàn)的方法來說,<T extends Animal>對T進行了限制,只能是Animal的子類。傳入Cat,就是Cat。
- 對于通配符實現(xiàn)的方法來說,相當于對Animal進行了規(guī)定,允許傳入Animal的子類。具體哪個子類,此時并不清楚。如:傳入Cat,實際上聲明的類型是Animal,使用多態(tài)才能調用Cat的toString方法
通配符上界→父子類關系:
//需要使用通配符來確定父子類型
MyArrayList<? extends Number>是MyArrayList<Integer>或者MyArrayList<Double>的父類
MyArrayList<?>是MyArrayList<? extends Number>的父類
ArrayList<Integer> arrayList1 = new ArrayList<>(); ArrayList<Double> arrayList2 = new ArrayList<>(); List<? extends Number> list = arrayList1; //list.add(1,1);//報錯,此時list的引用的子類對象有很多,再添加的時候,任何子類型都可以,為了安全,java不讓這樣進行添加操作。 Number a = list.get(0);//可以通過 Integer i = list.get(0);//編譯錯誤,只能確定是Number子類
【注】
- 不能對其進行添加,list中存儲的可能是Number也可能是Number的子類,無法確定類型。
- 通配符上界適合讀取,不適合寫入。
(2)通配符的下界
語法:
<? super 下界>
<? super Integer>//可以傳入的參數(shù)類型是Integer或者Integer的父類
通配符下界的父子類關系:
MyArrayList<? super Integer>是MyArrayList<Intrger>的父類類型
MyArrayList<?>是MyArrayList<? super Integer>的父類
通配符下界適合寫入元素,不適合讀取。
5、包裝類
在Java中,由于基本類型不是繼承自Object,為了在泛型中可以支持基本類型,每個基本類型都對應了一個包裝類。除了Integer和Character,其余基本類型的包裝類都是首字母大寫。
拆箱和裝箱:
int i=10; //裝箱操作,新建一個Integer類型對象,將i的值放入對象的某個屬性中 Integer ii=i; //自動裝箱 //Integer ii=Integer.valueOf(i); Integer ij= new Integer(i);//顯示裝箱 //拆箱操作,將Integer對象中的值取出,放到一個基本數(shù)據(jù)類型中 int j=ii.intValue();//顯示的拆箱 int jj=ii;//隱式的拆箱
到此這篇關于Java 深入淺出講解泛型與包裝類的文章就介紹到這了,更多相關Java 泛型 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決SpringBoot中MultipartResolver和ServletFileUpload的沖突問題
這篇文章主要介紹了解決SpringBoot中MultipartResolver和ServletFileUpload的沖突問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring ApplicationContext上下文核心容器深入探究
ApplicationContext是Spring應用程序中的中央接口,由于繼承了多個組件,使得ApplicationContext擁有了許多Spring的核心功能,如獲取bean組件,注冊監(jiān)聽事件,加載資源文件等2023-01-01
SpringBoot 項目如何在tomcat容器中運行的實現(xiàn)方法
這篇文章主要介紹了SpringBoot 項目如何在tomcat容器中運行的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09

