本篇文章為大家展示了Java常見(jiàn)知識(shí)點(diǎn)中的泛型指的是什么,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到東鄉(xiāng)網(wǎng)站設(shè)計(jì)與東鄉(xiāng)網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、申請(qǐng)域名、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋東鄉(xiāng)地區(qū)。
開(kāi)發(fā)人員在使用泛型的時(shí)候,很容易根據(jù)自己的直覺(jué)而犯一些錯(cuò)誤。比如一個(gè)方法如果接收List作為形式參數(shù),那么如果嘗試將一個(gè)List的對(duì)象作為實(shí)際參數(shù)傳進(jìn)去,卻發(fā)現(xiàn)無(wú)法通過(guò)編譯。雖然從直覺(jué)上來(lái)說(shuō),Object是String的父類,這種類型轉(zhuǎn)換應(yīng)該是合理的。但是實(shí)際上這會(huì)產(chǎn)生隱含的類型轉(zhuǎn)換問(wèn)題,因此編譯器直接就禁止這樣的行為。一. 類型擦除Java中的泛型基本上都是在編譯器這個(gè)層次來(lái)實(shí)現(xiàn)的,在生成的Java字節(jié)代碼中是不包含泛型中的類型信息的。使用泛型的時(shí)候加上的類型參數(shù),會(huì)被編譯器在編譯的時(shí)候去掉,這個(gè)過(guò)程就稱為類型擦除。如在代碼中定義的List和List等類型,在編譯之后都會(huì)變成List。JVM看到的只是List,而由泛型附加的類型信息對(duì)JVM來(lái)說(shuō)是不可見(jiàn)的。Java編譯器會(huì)在編譯時(shí)盡可能的發(fā)現(xiàn)可能出錯(cuò)的地方,但是仍然無(wú)法避免在運(yùn)行時(shí)刻出現(xiàn)類型轉(zhuǎn)換異常的情況。很多泛型的奇怪特性都與這個(gè)類型擦除的存在有關(guān),包括:泛型類并沒(méi)有自己獨(dú)有的Class類對(duì)象。比如并不存在List.class或是List.class,而只有List.class。靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對(duì)于聲明為MyClass的類,訪問(wèn)其中的靜態(tài)變量的方法仍然是 MyClass.myStaticVar。不管是通過(guò)new MyClass還是new MyClass創(chuàng)建的對(duì)象,都是共享一個(gè)靜態(tài)變量。泛型的類型參數(shù)不能用在Java異常處理的catch語(yǔ)句中。因?yàn)楫惓L幚硎怯蒍VM在運(yùn)行時(shí)刻來(lái)進(jìn)行的。由于類型信息被擦除,JVM是無(wú)法區(qū)分兩個(gè)異常類型MyException和MyException的。對(duì)于JVM來(lái)說(shuō),它們都是 MyException類型的。也就無(wú)法執(zhí)行與異常對(duì)應(yīng)的catch語(yǔ)句。類型擦除的基本過(guò)程也比較簡(jiǎn)單,首先是找到用來(lái)替換類型參數(shù)的具體類。這個(gè)具體類一般是Object。如果指定了類型參數(shù)的上界的話,則使用這個(gè)上界。把代碼中的類型參數(shù)都替換成具體的類。同時(shí)去掉出現(xiàn)的類型聲明,即去掉<>的內(nèi)容。比如T get()方法聲明就變成了Object get();List就變成了List。接下來(lái)就可能需要生成一些橋接方法(bridge method)。這是由于擦除了類型之后的類可能缺少某些必須的方法。比如考慮下面的代碼:class MyString implements Comparable<String> { public int compareTo(String str) { return 0; } }當(dāng)類型信息被擦除之后,上述類的聲明變成了class MyString implements Comparable。但是這樣的話,類MyString就會(huì)有編譯錯(cuò)誤,因?yàn)闆](méi)有實(shí)現(xiàn)接口Comparable聲明的int compareTo(Object)方法。這個(gè)時(shí)候就由編譯器來(lái)動(dòng)態(tài)生成這個(gè)方法。二. 通配符在使用泛型類的時(shí)候,既可以指定一個(gè)具體的類型,如List就聲明了具體的類型是String;也可以用通配符?來(lái)表示未知類型,如List<?>就聲明了List中包含的元素類型是未知的。 通配符所代表的其實(shí)是一組類型,但具體的類型是未知的。List<?>所聲明的就是所有類型都是可以的。但是List<?>并不等同于List。List實(shí)際上確定了List中包含的是Object及其子類,在使用的時(shí)候都可以通過(guò)Object來(lái)進(jìn)行引用。而List<?>其中所包含的元素類型是不確定。其中可能包含的是String,也可能是 Integer。如果它包含了String的話,往里面添加Integer類型的元素就是錯(cuò)誤的。正因?yàn)轭愋臀粗?,就不能通過(guò)new ArrayList()的方法來(lái)創(chuàng)建一個(gè)新的ArrayList對(duì)象。因?yàn)榫幾g器無(wú)法知道具體的類型是什么。但是對(duì)于 List中的元素確總是可以用Object來(lái)引用的,因?yàn)殡m然類型未知,但肯定是Object及其子類。考慮下面的代碼:public void wildcard(List<?> list) { list.add(1);//編譯錯(cuò)誤 }如上所示,試圖對(duì)一個(gè)帶通配符的泛型類進(jìn)行操作的時(shí)候,總是會(huì)出現(xiàn)編譯錯(cuò)誤。其原因在于通配符所表示的類型是未知的。因?yàn)閷?duì)于List<?>中的元素只能用Object來(lái)引用,在有些情況下不是很方便。在這些情況下,可以使用上下界來(lái)限制未知類型的范圍。 如 List<? extends Number>說(shuō)明List中可能包含的元素類型是Number及其子類。而List<? super Number>則說(shuō)明List中包含的是Number及其父類。當(dāng)引入了上界之后,在使用類型的時(shí)候就可以使用上界類中定義的方法。三. 類型系統(tǒng)在Java中,大家比較熟悉的是通過(guò)繼承機(jī)制而產(chǎn)生的類型體系結(jié)構(gòu)。比如String繼承自O(shè)bject。根據(jù)Liskov替換原則,子類是可以替換父類的。當(dāng)需要Object類的引用的時(shí)候,如果傳入一個(gè)String對(duì)象是沒(méi)有任何問(wèn)題的。但是反過(guò)來(lái)的話,即用父類的引用替換子類引用的時(shí)候,就需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。編譯器并不能保證運(yùn)行時(shí)刻這種轉(zhuǎn)換一定是合法的。這種自動(dòng)的子類替換父類的類型轉(zhuǎn)換機(jī)制,對(duì)于數(shù)組也是適用的。 String[]可以替換Object[]。但是泛型的引入,對(duì)于這個(gè)類型系統(tǒng)產(chǎn)生了一定的影響。正如前面提到的List是不能替換掉List的。引入泛型之后的類型系統(tǒng)增加了兩個(gè)維度:一個(gè)是類型參數(shù)自身的繼承體系結(jié)構(gòu),另外一個(gè)是泛型類或接口自身的繼承體系結(jié)構(gòu)。第一個(gè)指的是對(duì)于 List和List這樣的情況,類型參數(shù)String是繼承自O(shè)bject的。而第二種指的是 List接口繼承自Collection接口。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則:相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。即List是Collection的子類型,List可以替換Collection。這種情況也適用于帶有上下界的類型聲明。當(dāng)泛型類的類型聲明中使用了通配符的時(shí)候,其子類型可以在兩個(gè)維度上分別展開(kāi)。如對(duì)Collection<? extends Number>來(lái)說(shuō),其子類型可以在Collection這個(gè)維度上展開(kāi),即List<? extends Number>和Set<? extends Number>等;也可以在Number這個(gè)層次上展開(kāi),即Collection和Collection等。如此循環(huán)下去,ArrayList和 HashSet等也都算是Collection<? extends Number>的子類型。如果泛型類中包含多個(gè)類型參數(shù),則對(duì)于每個(gè)類型參數(shù)分別應(yīng)用上面的規(guī)則。
Java中的泛型基本上都是在編譯器這個(gè)層次來(lái)實(shí)現(xiàn)的,在生成的Java字節(jié)代碼中是不包含泛型中的類型信息的。使用泛型的時(shí)候加上的類型參數(shù),會(huì)被編譯器在編譯的時(shí)候去掉,這個(gè)過(guò)程就稱為類型擦除。如在代碼中定義的List和List等類型,在編譯之后都會(huì)變成List。JVM看到的只是List,而由泛型附加的類型信息對(duì)JVM來(lái)說(shuō)是不可見(jiàn)的。Java編譯器會(huì)在編譯時(shí)盡可能的發(fā)現(xiàn)可能出錯(cuò)的地方,但是仍然無(wú)法避免在運(yùn)行時(shí)刻出現(xiàn)類型轉(zhuǎn)換異常的情況。很多泛型的奇怪特性都與這個(gè)類型擦除的存在有關(guān),包括:泛型類并沒(méi)有自己獨(dú)有的Class類對(duì)象。比如并不存在List.class或是List.class,而只有List.class。靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對(duì)于聲明為MyClass的類,訪問(wèn)其中的靜態(tài)變量的方法仍然是 MyClass.myStaticVar。不管是通過(guò)new MyClass還是new MyClass創(chuàng)建的對(duì)象,都是共享一個(gè)靜態(tài)變量。泛型的類型參數(shù)不能用在Java異常處理的catch語(yǔ)句中。因?yàn)楫惓L幚硎怯蒍VM在運(yùn)行時(shí)刻來(lái)進(jìn)行的。由于類型信息被擦除,JVM是無(wú)法區(qū)分兩個(gè)異常類型MyException和MyException的。對(duì)于JVM來(lái)說(shuō),它們都是 MyException類型的。也就無(wú)法執(zhí)行與異常對(duì)應(yīng)的catch語(yǔ)句。類型擦除的基本過(guò)程也比較簡(jiǎn)單,首先是找到用來(lái)替換類型參數(shù)的具體類。這個(gè)具體類一般是Object。如果指定了類型參數(shù)的上界的話,則使用這個(gè)上界。把代碼中的類型參數(shù)都替換成具體的類。同時(shí)去掉出現(xiàn)的類型聲明,即去掉<>的內(nèi)容。比如T get()方法聲明就變成了Object get();List就變成了List。接下來(lái)就可能需要生成一些橋接方法(bridge method)。這是由于擦除了類型之后的類可能缺少某些必須的方法。比如考慮下面的代碼:class MyString implements Comparable<String> { public int compareTo(String str) { return 0; } }當(dāng)類型信息被擦除之后,上述類的聲明變成了class MyString implements Comparable。但是這樣的話,類MyString就會(huì)有編譯錯(cuò)誤,因?yàn)闆](méi)有實(shí)現(xiàn)接口Comparable聲明的int compareTo(Object)方法。這個(gè)時(shí)候就由編譯器來(lái)動(dòng)態(tài)生成這個(gè)方法。二. 通配符在使用泛型類的時(shí)候,既可以指定一個(gè)具體的類型,如List就聲明了具體的類型是String;也可以用通配符?來(lái)表示未知類型,如List<?>就聲明了List中包含的元素類型是未知的。 通配符所代表的其實(shí)是一組類型,但具體的類型是未知的。List<?>所聲明的就是所有類型都是可以的。但是List<?>并不等同于List。List實(shí)際上確定了List中包含的是Object及其子類,在使用的時(shí)候都可以通過(guò)Object來(lái)進(jìn)行引用。而List<?>其中所包含的元素類型是不確定。其中可能包含的是String,也可能是 Integer。如果它包含了String的話,往里面添加Integer類型的元素就是錯(cuò)誤的。正因?yàn)轭愋臀粗?,就不能通過(guò)new ArrayList()的方法來(lái)創(chuàng)建一個(gè)新的ArrayList對(duì)象。因?yàn)榫幾g器無(wú)法知道具體的類型是什么。但是對(duì)于 List中的元素確總是可以用Object來(lái)引用的,因?yàn)殡m然類型未知,但肯定是Object及其子類。考慮下面的代碼:public void wildcard(List<?> list) { list.add(1);//編譯錯(cuò)誤 }如上所示,試圖對(duì)一個(gè)帶通配符的泛型類進(jìn)行操作的時(shí)候,總是會(huì)出現(xiàn)編譯錯(cuò)誤。其原因在于通配符所表示的類型是未知的。因?yàn)閷?duì)于List<?>中的元素只能用Object來(lái)引用,在有些情況下不是很方便。在這些情況下,可以使用上下界來(lái)限制未知類型的范圍。 如 List<? extends Number>說(shuō)明List中可能包含的元素類型是Number及其子類。而List<? super Number>則說(shuō)明List中包含的是Number及其父類。當(dāng)引入了上界之后,在使用類型的時(shí)候就可以使用上界類中定義的方法。三. 類型系統(tǒng)在Java中,大家比較熟悉的是通過(guò)繼承機(jī)制而產(chǎn)生的類型體系結(jié)構(gòu)。比如String繼承自O(shè)bject。根據(jù)Liskov替換原則,子類是可以替換父類的。當(dāng)需要Object類的引用的時(shí)候,如果傳入一個(gè)String對(duì)象是沒(méi)有任何問(wèn)題的。但是反過(guò)來(lái)的話,即用父類的引用替換子類引用的時(shí)候,就需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。編譯器并不能保證運(yùn)行時(shí)刻這種轉(zhuǎn)換一定是合法的。這種自動(dòng)的子類替換父類的類型轉(zhuǎn)換機(jī)制,對(duì)于數(shù)組也是適用的。 String[]可以替換Object[]。但是泛型的引入,對(duì)于這個(gè)類型系統(tǒng)產(chǎn)生了一定的影響。正如前面提到的List是不能替換掉List的。引入泛型之后的類型系統(tǒng)增加了兩個(gè)維度:一個(gè)是類型參數(shù)自身的繼承體系結(jié)構(gòu),另外一個(gè)是泛型類或接口自身的繼承體系結(jié)構(gòu)。第一個(gè)指的是對(duì)于 List和List這樣的情況,類型參數(shù)String是繼承自O(shè)bject的。而第二種指的是 List接口繼承自Collection接口。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則:相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。即List是Collection的子類型,List可以替換Collection。這種情況也適用于帶有上下界的類型聲明。當(dāng)泛型類的類型聲明中使用了通配符的時(shí)候,其子類型可以在兩個(gè)維度上分別展開(kāi)。如對(duì)Collection<? extends Number>來(lái)說(shuō),其子類型可以在Collection這個(gè)維度上展開(kāi),即List<? extends Number>和Set<? extends Number>等;也可以在Number這個(gè)層次上展開(kāi),即Collection和Collection等。如此循環(huán)下去,ArrayList和 HashSet等也都算是Collection<? extends Number>的子類型。如果泛型類中包含多個(gè)類型參數(shù),則對(duì)于每個(gè)類型參數(shù)分別應(yīng)用上面的規(guī)則。
很多泛型的奇怪特性都與這個(gè)類型擦除的存在有關(guān),包括:
泛型類并沒(méi)有自己獨(dú)有的Class類對(duì)象。比如并不存在List
靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對(duì)于聲明為MyClass
泛型的類型參數(shù)不能用在Java異常處理的catch語(yǔ)句中。因?yàn)楫惓L幚硎怯蒍VM在運(yùn)行時(shí)刻來(lái)進(jìn)行的。由于類型信息被擦除,JVM是無(wú)法區(qū)分兩個(gè)異常類型MyException
類型擦除的基本過(guò)程也比較簡(jiǎn)單,首先是找到用來(lái)替換類型參數(shù)的具體類。這個(gè)具體類一般是Object。如果指定了類型參數(shù)的上界的話,則使用這個(gè)上界。把代碼中的類型參數(shù)都替換成具體的類。同時(shí)去掉出現(xiàn)的類型聲明,即去掉<>的內(nèi)容。比如T get()方法聲明就變成了Object get();List就變成了List。接下來(lái)就可能需要生成一些橋接方法(bridge method)。這是由于擦除了類型之后的類可能缺少某些必須的方法。比如考慮下面的代碼:
class MyString implements Comparable<String> { public int compareTo(String str) { return 0; } }
當(dāng)類型信息被擦除之后,上述類的聲明變成了class MyString implements Comparable。但是這樣的話,類MyString就會(huì)有編譯錯(cuò)誤,因?yàn)闆](méi)有實(shí)現(xiàn)接口Comparable聲明的int compareTo(Object)方法。這個(gè)時(shí)候就由編譯器來(lái)動(dòng)態(tài)生成這個(gè)方法。
在使用泛型類的時(shí)候,既可以指定一個(gè)具體的類型,如List就聲明了具體的類型是String;也可以用通配符?來(lái)表示未知類型,如List<?>就聲明了List中包含的元素類型是未知的。 通配符所代表的其實(shí)是一組類型,但具體的類型是未知的。List<?>所聲明的就是所有類型都是可以的。但是List<?>并不等同于List。List實(shí)際上確定了List中包含的是Object及其子類,在使用的時(shí)候都可以通過(guò)Object來(lái)進(jìn)行引用。而List<?>其中所包含的元素類型是不確定。其中可能包含的是String,也可能是 Integer。如果它包含了String的話,往里面添加Integer類型的元素就是錯(cuò)誤的。正因?yàn)轭愋臀粗?,就不能通過(guò)new ArrayList()的方法來(lái)創(chuàng)建一個(gè)新的ArrayList對(duì)象。因?yàn)榫幾g器無(wú)法知道具體的類型是什么。但是對(duì)于 List中的元素確總是可以用Object來(lái)引用的,因?yàn)殡m然類型未知,但肯定是Object及其子類。考慮下面的代碼:
public void wildcard(List<?> list) { list.add(1);//編譯錯(cuò)誤 }
如上所示,試圖對(duì)一個(gè)帶通配符的泛型類進(jìn)行操作的時(shí)候,總是會(huì)出現(xiàn)編譯錯(cuò)誤。其原因在于通配符所表示的類型是未知的。
因?yàn)閷?duì)于List<?>中的元素只能用Object來(lái)引用,在有些情況下不是很方便。在這些情況下,可以使用上下界來(lái)限制未知類型的范圍。 如 List<? extends Number>說(shuō)明List中可能包含的元素類型是Number及其子類。而List<? super Number>則說(shuō)明List中包含的是Number及其父類。當(dāng)引入了上界之后,在使用類型的時(shí)候就可以使用上界類中定義的方法。
在Java中,大家比較熟悉的是通過(guò)繼承機(jī)制而產(chǎn)生的類型體系結(jié)構(gòu)。比如String繼承自O(shè)bject。根據(jù)Liskov替換原則,子類是可以替換父類的。當(dāng)需要Object類的引用的時(shí)候,如果傳入一個(gè)String對(duì)象是沒(méi)有任何問(wèn)題的。但是反過(guò)來(lái)的話,即用父類的引用替換子類引用的時(shí)候,就需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。編譯器并不能保證運(yùn)行時(shí)刻這種轉(zhuǎn)換一定是合法的。這種自動(dòng)的子類替換父類的類型轉(zhuǎn)換機(jī)制,對(duì)于數(shù)組也是適用的。 String[]可以替換Object[]。但是泛型的引入,對(duì)于這個(gè)類型系統(tǒng)產(chǎn)生了一定的影響。正如前面提到的List是不能替換掉List的。
引入泛型之后的類型系統(tǒng)增加了兩個(gè)維度:一個(gè)是類型參數(shù)自身的繼承體系結(jié)構(gòu),另外一個(gè)是泛型類或接口自身的繼承體系結(jié)構(gòu)。第一個(gè)指的是對(duì)于 List和List這樣的情況,類型參數(shù)String是繼承自O(shè)bject的。而第二種指的是 List接口繼承自Collection接口。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則:
相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。即List
當(dāng)泛型類的類型聲明中使用了通配符的時(shí)候,其子類型可以在兩個(gè)維度上分別展開(kāi)。如對(duì)Collection<? extends Number>來(lái)說(shuō),其子類型可以在Collection這個(gè)維度上展開(kāi),即List<? extends Number>和Set<? extends Number>等;也可以在Number這個(gè)層次上展開(kāi),即Collection
如果泛型類中包含多個(gè)類型參數(shù),則對(duì)于每個(gè)類型參數(shù)分別應(yīng)用上面的規(guī)則。
上述內(nèi)容就是Java常見(jiàn)知識(shí)點(diǎn)中的泛型指的是什么,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站標(biāo)題:Java常見(jiàn)知識(shí)點(diǎn)中的泛型指的是什么 文章鏈接:http://www.rwnh.cn/article38/psjopp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、響應(yīng)式網(wǎng)站、云服務(wù)器、虛擬主機(jī)、、網(wǎng)站內(nèi)鏈
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
網(wǎng)站設(shè)計(jì)公司知識(shí)
同城分類信息