網(wǎng)頁小游戲在線玩知乎北京網(wǎng)站快速優(yōu)化排名
?泛型:定義階段不明確具體類型,產(chǎn)生對象時(shí)明確具體類型。
//Object是Java中的最高參數(shù)統(tǒng)一化,能夠接受所有的引用類型;
//有了包裝類的自動(dòng)拆裝箱之后,Object還能夠接收基本類型數(shù)值(自動(dòng)裝箱)
public class Pointer {private Object x;private Object y;public void setX(Object x) {this.x = x;}public void setY(Object y) {this.y = y;}public Object getX() {return x;}public Object getY() {return y;}public static void main(String[] args) {//此時(shí)x和y都由用戶進(jìn)行輸入//第一組為整型Pointer p1=new Pointer();p1.setX(10);p1.setY(20);System.out.println("x="+p1.getX()+",y="+p1.getY());//第二組為字符串Pointer p2=new Pointer();p2.setX("東經(jīng)108度");p2.setY("北緯18度");System.out.println("x="+p2.getX()+",y="+p2.getY());//第三種情況:用戶進(jìn)行輸入//編譯階段不會(huì)出現(xiàn)問題,但是運(yùn)行期間會(huì)報(bào)錯(cuò)//錯(cuò)誤原因:由于用戶的異常輸入,導(dǎo)致程序類型轉(zhuǎn)換異常,當(dāng)出現(xiàn)異常后,程序就退出了。Pointer p3=new Pointer();p3.setX(10);p3.setY("北緯100度");int x=(int)p3.getX();int y=(int)p3.getY();System.out.println("x="+x+",y="+y);}
}
針對于某些需要多種類型的輸入的情況,一般大家會(huì)想到采用Object進(jìn)行變量類型定義,但是這種定義變量的方式會(huì)存在以下問題:
Object雖然可以接收所有的類型,但是Object轉(zhuǎn)為其他類型都需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,只要是強(qiáng)轉(zhuǎn)都有類型出錯(cuò)的風(fēng)險(xiǎn),調(diào)用getX和getY方法時(shí),需要根據(jù)具體的類型,將Object強(qiáng)轉(zhuǎn)為具體的子類(隱藏的風(fēng)險(xiǎn),此風(fēng)險(xiǎn)會(huì)發(fā)生在運(yùn)行期間)。
因此,需要有新的機(jī)制,可以在定義類時(shí),成員變量可以接收多種類型,但是在具體產(chǎn)生對象時(shí)明確類型,當(dāng)有不同類型設(shè)置時(shí),編譯階段就能發(fā)現(xiàn)錯(cuò)誤。
JDK1.5引入的泛型機(jī)制。所謂的泛型,就是在定義類或方法時(shí),沒有明確參數(shù)的類型,而是在使用該類時(shí),明確類型。不需要進(jìn)行類型強(qiáng)轉(zhuǎn),編譯階段就會(huì)在語法階段檢查類型是否匹配的機(jī)制。
將泛型比作為類型編譯階段守門員,不會(huì)讓類型不匹配的問題進(jìn)入到運(yùn)行階段。
1. 泛型類的使用
(1)語法
類名稱?<類型參數(shù)> {? //類型參數(shù)用大寫英文字母來代替,任何一個(gè)都可以
類型參數(shù)? 成員變量名稱;
...
}
泛型類的使用示例:
public class Point<T> {private T x;private T y;public void setX(T x) {this.x = x;}public void setY(T y) {this.y = y;}public T getX() {return x;}public T getY() {return y;}
}
由于此時(shí)變量具體類型未知,因此,此處的T只是一個(gè)指代,寫什么都行。一般采用大寫的單個(gè)字母定義。
此處x和y的類型未知,但是可以保證它們是同一個(gè)類型,因?yàn)槭褂昧讼嗤念愋蛥?shù)T。
(2)根據(jù)泛型類,產(chǎn)生泛型對象
泛型類在定義時(shí),可以不明確成員變量的類型,但是在產(chǎn)生對象時(shí),必須明確類型。
public static void main(String[] args) {//產(chǎn)生泛型類對象//此時(shí)產(chǎn)生的是Integer類型的Point對象,此時(shí)的x和y就會(huì)被定義為整型Point<Integer> point=new Point<>();//此處不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,且能夠在編譯階段檢查設(shè)置類型是否滿足要求(編譯階段就會(huì)報(bào)錯(cuò),不會(huì)在運(yùn)行期間出錯(cuò))int x= point.getX();int y= point.getY();}
此處不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,且能夠在編譯階段檢查設(shè)置類型是否滿足要求(如果出錯(cuò),編譯階段就會(huì)報(bào)錯(cuò),不會(huì)在運(yùn)行期間出錯(cuò))。
(3)泛型類使用多個(gè)類型參數(shù)
泛型類名稱<類型參數(shù)1,類型參數(shù)2,....>{
? ? ? ? 類型參數(shù)1 變量x;
? ? ? ? 類型參數(shù)2 變量y;
? ? ? ? //.....
}
?定義:一般使用多個(gè)大寫字母來定義類型參數(shù)
- T=>一般指代任何類均可
- E=>一般代表元素Element和T意義差不多,也有使用E來指代異常的意思
K和V一般搭配使用,描述一個(gè)鍵值對的對象。
- K=>key的意思,不重復(fù)的鍵值
- V=>value的意思,可以重復(fù)
public class NewPoint<T,E> {private T x;private E y;public T getX() { return x; }public void setX(T x) { this.x = x;}public E getY() {return y;}public void setY(E y) {this.y = y;}
}
?產(chǎn)生對象:x和y的類型可以相同,也可以不同
public static void main(String[] args) {NewPoint<Integer,String> newpoint=new NewPoint<>();newpoint.set}
?2. 泛型方法
?泛型不僅可以定義一個(gè)類,也可以單獨(dú)定義方法。
(1)語法
權(quán)限修飾符<類型參數(shù)>?方法返回值類型 方法名稱(類型參數(shù)? 形參名稱){
????????.......
}
泛型方法以自己的類型參數(shù)為準(zhǔn),為了區(qū)分和泛型類的類型參數(shù),一般若泛型類中存在泛型方法,使用不同的類型參數(shù)。(E代表類型不一樣)
當(dāng)泛型類和泛型方法共存時(shí),?泛型方法始終以自己的類型參數(shù)為準(zhǔn)。
3. 泛型的注意點(diǎn)
- 泛型只能用在成員域,不能用在靜態(tài)域(static修飾的內(nèi)容不能使用泛型)
- 產(chǎn)生泛型對象時(shí),具體的類型不能使用基本數(shù)據(jù)類型,要用基本類型的話統(tǒng)一使用包裝類
- 不能直接創(chuàng)建和實(shí)例化泛型數(shù)組,要使用泛型數(shù)組,統(tǒng)一使用Object數(shù)組
這三個(gè)問題的本質(zhì)在于泛型只存在于編譯階段,運(yùn)行階段沒有泛型(類型擦除)
4. 泛型的類型擦除問題
類型擦除:泛型信息只存在于編譯階段,在進(jìn)入JVM之前,與泛型有關(guān)的所有信息會(huì)被編譯器擦除掉,專業(yè)術(shù)語稱為“類型擦除”。
運(yùn)行階段沒有任何與泛型相關(guān)的信息。
利用反射進(jìn)行觀察:
?泛型只存在于程序的編譯階段,當(dāng)javac將代碼編譯為class文件之后,與泛型相關(guān)的所有信息全部被擦除掉了。
- 一般的泛型都會(huì)擦除為Object類型;
- 若存在泛型上限,擦除為對應(yīng)的泛型上限。