新聞中心
我們都知道Java 在 1.5 引入了泛型機制,泛型的本質(zhì)是參數(shù)化類型,也就是說變量的類型是一個參數(shù),在使用時再指定為具體類型。泛型可以用于類、接口、方法,通過使用泛型可以使代碼更簡單、安全。本文通過參考《Java編程思想》對泛型使用過程中需要注意的問題進行了總結(jié)以及給大家提供一些泛型相關(guān)的面試題供大家學(xué)習(xí)使用。

成都創(chuàng)新互聯(lián)公司是專業(yè)的麻章網(wǎng)站建設(shè)公司,麻章接單;提供網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行麻章網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
泛型相關(guān)問題
1、泛型類型引用傳遞問題
在 Java 中,像下面形式的引用傳遞是不允許的:
- ArrayList
arrayList1=new ArrayList - ArrayList
我們先看第一種情況,將第一種情況拓展成下面的形式:
- ArrayList
- arrayList1.add(new Object());
- arrayList1.add(new Object());
- ArrayList
arrayList2=arrayList1;//編譯錯誤
實際上,在第 4 行代碼處,就會有編譯錯誤。那么,我們先假設(shè)它編譯沒錯。那么當(dāng)我們使用arrayList2 引用用 get()方法取值的時候,返回的都是 String 類型的對象,可是它里面實際上已經(jīng)被我們存放了 Object 類型的對象,這樣,就會有 ClassCastException 了。所以為了避免這種極易出現(xiàn)的錯誤,Java 不允許進行這樣的引用傳遞。(這也是泛型出現(xiàn)的原因,就是為了解決類型轉(zhuǎn)換的問題,我們不能違背它的初衷)。
在看第二種情況,將第二種情況拓展成下面的形式:
- ArrayList
arrayList1=new ArrayList (); - arrayList1.add(new String());
- arrayList1.add(new String());
- ArrayList
arrayList2=arrayList1;//編譯錯誤
沒錯,這樣的情況比第一種情況好的多,最起碼,在我們用 arrayList2 取值的時候不會出現(xiàn)ClassCastException,因為是從 String 轉(zhuǎn)換為 Object??墒?,這樣做有什么意義呢,泛型出現(xiàn)的原因,就是為了解決類型轉(zhuǎn)換的問題。我們使用了泛型,到頭來,還是要自己強轉(zhuǎn),違背了泛型設(shè)計的初衷。所以 java 不允許這么干。再說,你如果又用 arrayList2 往里面 add()新的對象,那么到時候取得時候,我怎么知道我取出來的到底是 String 類型的,還是 Object 類型的呢?所以,要格外注意泛型中引用傳遞問題。
2、泛型類型變量不能是基本數(shù)據(jù)類型
就比如,沒有 ArrayList
3、運行時類型查詢
- ArrayList
arrayList=new ArrayList ();if( arrayList instanceof ArrayLi
因為類型擦除之后,ArrayList
4、泛型在靜態(tài)方法和靜態(tài)類中的問題
泛型類中的靜態(tài)方法和靜態(tài)變量不可以使用泛型類所聲明的泛型類型參數(shù)
- public class Test2
{ - public static T one; //編譯錯誤
- public static T show(T one){ //編譯錯誤
- return null;
- } }
因為泛型類中的泛型參數(shù)的實例化是在定義泛型類型對象(例如 ArrayList
但是要注意區(qū)分下面的一種情況:
- public class Test2
{ - public static
T show(T one){//這是正確的 - return null;
- } }
因為這是一個泛型方法,在泛型方法中使用的 T 是自己在方法中定義的 T,而不是泛型類中的 T。
泛型相關(guān)面試題
1. Java 中的泛型是什么 ? 使用泛型的好處是什么?
泛型是一種參數(shù)化類型的機制。它可以使得代碼適用于各種類型,從而編寫更加通用的代碼,例如集合框架。泛型是一種編譯時類型確認機制。它提供了編譯期的類型安全,確保在泛型類型(通常為泛型集合)上只能使用正確類型的對象,避免了在運行時出現(xiàn) ClassCastException。
2、Java 的泛型是如何工作的 ? 什么是類型擦除 ?
泛型的正常工作是依賴編譯器在編譯源碼的時候,先進行類型檢查,然后進行類型擦除并且在類型參數(shù)出現(xiàn)的地方插入強制轉(zhuǎn)換的相關(guān)指令實現(xiàn)的。
編譯器在編譯時擦除了所有類型相關(guān)的信息,所以在運行時不存在任何類型相關(guān)的信息。例如List
3. 什么是泛型中的限定通配符和非限定通配符 ?
限定通配符對類型進行了限制。有兩種限定通配符,一種是 extends T>它通過確保類型必須是 T 的子類來設(shè)定類型的上界,另一種是 super T>它通過確保類型必須是 T 的父類來設(shè)定類型的下界。泛型類型必須用限定內(nèi)的類型來進行初始化,否則會導(dǎo)致編譯錯誤。另一方面>表示了非限定通配符,因為>可以用任意類型來替代。
4. List extends T>和 List super T>之間有什么區(qū)別 ?
這和上一個面試題有聯(lián)系,有時面試官會用這個問題來評估你對泛型的理解,而不是直接問你什么是限定通配符和非限定通配符。這兩個 List 的聲明都是限定通配符的例子,List extends T>可以接受任何繼承自 T 的類型的 List,而 List super T>可以接受任何 T 的父類構(gòu)成的 List。例如 List可以接受 List
5. 如何編寫一個泛型方法,讓它能接受泛型參數(shù)并返回泛型類型?
編寫泛型方法并不困難,你需要用泛型類型來替代原始類型,比如使用 T, E or K,V 等被廣泛認可的類型占位符。泛型方法的例子請參閱 Java 集合類框架。最簡單的情況下,一個泛型方法可能會像這樣:
- public V put(K key, V value) {
- return cache.put(key, value);
- }
6. Java 中如何使用泛型編寫帶有參數(shù)的類?
這是上一道面試題的延伸。面試官可能會要求你用泛型編寫一個類型安全的類,而不是編寫一個泛型方法。關(guān)鍵仍然是使用泛型類型來代替原始類型,而且要使用 JDK 中采用的標(biāo)準占位符。
7. 編寫一段泛型程序來實現(xiàn) LRU 緩存?
對于喜歡 Java 編程的人來說這相當(dāng)于是一次練習(xí)。給你個提示,LinkedHashMap 可以用來實現(xiàn)固定大小的 LRU 緩存,當(dāng) LRU 緩存已經(jīng)滿了的時候,它會把最老的鍵值對移出緩存。LinkedHashMap 提供了一個稱為 removeEldestEntry()的方法,該方法會被 put()和 putAll()調(diào)用來刪除最老的鍵值對。
8. 你可以把 List
對任何一個不太熟悉泛型的人來說,這個 Java 泛型題目看起來令人疑惑,因為乍看起來 String 是一種Object,所以 List
9. Array 中可以用泛型嗎?
這可能是 Java 泛型面試題中最簡單的一個了,當(dāng)然前提是你要知道 Array 事實上并不支持泛型,這也是為什么 Joshua Bloch 在 Effective Java 一書中建議使用 List 來代替 Array,因為 List 可以提供編譯期的類型安全保證,而 Array 卻不能。
10. 如何阻止 Java 中的類型未檢查的警告?
如果你把泛型和原始類型混合起來使用,例如下列代碼,Java 5 的 javac 編譯器會產(chǎn)生類型未檢查的警告,例如 List
11、Java 中 List
原始類型和帶參數(shù)類型
12、Java 中 List>和 List
這道題跟上一道題看起來很像,實質(zhì)上卻完全不同。List> 是一個未知類型的 List,而List
- List> listOfAnyType;
- List
listOfObject = new ArrayList (); - List
listOfString = new ArrayList (); - List
listOfInteger = new ArrayList (); - listOfAnyType = listOfString; //legal
- listOfAnyType = listOfInteger; //legal
- listOfObjectType = (List
) listOfString; //compiler error - in-convertible ty
13、List
該題類似于“原始類型和帶參數(shù)類型之間有什么區(qū)別”。帶參數(shù)類型是類型安全的,而且其類型安全是由編譯器保證的,但原始類型 List 卻不是類型安全的。你不能把 String 之外的任何其它類型的 Object 存入String 類型的 List 中,而你可以把任何類型的對象存入原始 List 中。使用泛型的帶參數(shù)類型你不需要進行類型轉(zhuǎn)換,但是對于原始類型,你則需要進行顯式的類型轉(zhuǎn)換。
- List listOfRawTypes = new ArrayList();
- listOfRawTypes.add("abc");
- listOfRawTypes.add(123); //編譯器允許這樣 - 運行時卻會出現(xiàn)異常
- String item = (String) listOfRawTypes.get(0); //需要顯式的類型轉(zhuǎn)換
- item = (String) listOfRawTypes.get(1); //拋 ClassCastException,因為 Integer 不能被轉(zhuǎn)換為 String
- List
listOfString = new ArrayList(); - listOfString.add("abcd");
- listOfString.add(1234); //編譯錯誤,比在運行時拋異常要好
- item = listOfString.get(0); //不需要顯式的類型轉(zhuǎn)換 - 編譯器自動轉(zhuǎn)換
通配符
通配符上界
常規(guī)使用
- public class Test {
- public static void printIntValue(List extends Number> list) {
- for (Number number : list) {
- System.out.print(number.intValue()+" ");
- }
- System.out.println();
- }
- public static void main(String[] args) {
- List
integerList=new ArrayList (); - integerList.add(2);
- integerList.add(2);
- printIntValue(integerList);
- List
floatList=new ArrayList (); - floatList.add((float) 3.3);
- floatList.add((float) 0.3);
- printIntValue(floatList);
- } }
輸出:
2 2
3 0
非法使用
- public class Test {
- public static void fillNumberList(List extends Number> list) {
- list.add(new Integer(0));//編譯錯誤
- list.add(new Float(1.0));//編譯錯誤
- }
- public static void main(String[] args) {
- List extends Number> list=new ArrayList();
- list.add(new Integer(1));//編譯錯誤
- list.add(new Float(1.0));//編譯錯誤
- } }
List extends Number>可以代表 List
首先,我們知道 List
- List extends Number> list1=new ArrayList
(); - List extends Number> list2=new ArrayList
();
假設(shè)前面的例子沒有編譯錯誤,如果我們把 list1 或者 list2 傳入方法 fillNumberList,顯然都會出現(xiàn)類型不匹配的情況,假設(shè)不成立。
因此,我們得出結(jié)論:不能往 List extends T> 中添加任意對象,除了 null。
那為什么對 List extends T>進行迭代可以呢,因為子類必定有父類相同的接口,這正是我們所期望的。
通配符下界
常規(guī)使用
- public class Test {
- public static void fillNumberList(List super Number> list) {
- list.add(new Integer(0));
- list.add(new Float(1.0));
- }
- public static void main(String[] args) {
- List super Number> list=new ArrayList();
- list.add(new Integer(1));
- list.add(new Float(1.1));
- } }
可以添加 Number 的任何子類,為什么呢?
List super Number>可以代表 List
非法使用
對 List superT>進行迭代是不允許的。為什么呢?你知道用哪種接口去迭代 List 嗎?只有用 Object類的接口才能保證集合中的元素都擁有該接口,顯然這個意義不大。其應(yīng)用場景略。
無界通配符
知道了通配符的上界和下界,其實也等同于知道了無界通配符,不加任何修飾即可,單獨一個“?”。如List>,“?”可以代表任意類型,“任意”也就是未知類型。
List
常規(guī)使用
1、當(dāng)方法是使用原始的 Object 類型作為參數(shù)時,如下:
- public static void printList(List
list) { - for (Object elem : list)
- System.out.println(elem + "");
- System.out.println();
- }
可以選擇改為如下實現(xiàn):
- public static void printList(List> list) {
- for (Object elem: list)
- System.out.print(elem + "");
- System.out.println();
- }
這樣就可以兼容更多的輸出,而不單純是 List
- List
li = Arrays.asList(1, 2, 3); - List
ls = Arrays.asList("one", "two", "three"); - printList(li);
- printList(ls);
分享題目:Java泛型需要注意的問題
當(dāng)前地址:http://www.dlmjj.cn/article/cdgdgde.html


咨詢
建站咨詢
