10道關於Java泛型的面試題

1. java中的泛型是什麼 ? 使用泛型的好處是什麼?

這是在各種java泛型面試中,一開場你就會被問到的問題中的一個,主要集中在初級和中級面試中。那些擁有java1.4或更早版本的開發背景的人 都知道,在集合中存儲對象並在使用前進行類型轉換是多么的不方便。泛型防止了那種情況的發生。它提供了編譯期的類型安全,確保你只能把正確類型的對象放入 集合中,避免了在運行時出現classcastexception。

2. java的泛型是如何工作的 ? 什麼是類型擦除 ?

這是一道更好的泛型面試題。泛型是通過類型擦除來實現的,編譯器在編譯時擦除了所有類型相關的信息,所以在運行時不存在任何類型相關的信息。例如 list<string>在運行時僅用一個list來表示。這樣做的目的,是確保能和java 5之前的版本開發二進制類庫進行兼容。你無法在運行時訪問到類型參數,因為編譯器已經把泛型類型轉換成了原始類型。根據你對這個泛型問題的回答情況,你會 得到一些後續提問,比如為什麼泛型是由類型擦除來實現的或者給你展示一些會導致編譯器出錯的錯誤泛型代碼。請閱讀我的java中泛型是如何工作的來了解更 多信息。

3. 什麼是泛型中的限定通配符和非限定通配符 ?

這是另一個非常流行的java泛型面試題。限定通配符對類型進行了限制。有兩種限定通配符,一種是<? extends t>它通過確保類型必須是t的子類來設定類型的上界,另一種是<? super t>它通過確保類型必須是t的父類來設定類型的下界。泛型類型必須用限定內的類型來進行初始化,否則會導致編譯錯誤。另一方面<?>表 示了非限定通配符,因為<?>可以用任意類型來替代。更多信息請參閱我的文章泛型中限定通配符和非限定通配符之間的區別。

4. list<? extends t>和list <? super t>之間有什麼區別 ?

這和上一個面試題有聯繫,有時面試官會用這個問題來評估你對泛型的理解,而不是直接問你什麼是限定通配符和非限定通配符。這兩個list的聲明都是 限定通配符的例子,list<? extends t>可以接受任何繼承自t的類型的list,而list<? super t>可以接受任何t的父類構成的list。例如list<? extends number>可以接受list<integer>或list<float>。在本段出現的連線中可以找到更多信息。

5. 如何編寫一個泛型方法,讓它能接受泛型參數並返回泛型類型?

編寫泛型方法並不困難,你需要用泛型類型來替代原始類型,比如使用t, e or k,v等被廣泛認可的類型占位符。泛型方法的例子請參閱java集合類框架。最簡單的情況下,一個泛型方法可能會像這樣:

public v put(k key, v value) {

return cache.put(key, value);

}

6. java中如何使用泛型編寫帶有參數的類?

這是上一道面試題的延伸。面試官可能會要求你用泛型編寫一個類型安全的類,而不是編寫一個泛型方法。關鍵仍然是使用泛型類型來代替原始類型,而且要使用jdk中採用的標準占位符。

7. 編寫一段泛型程式來實現lru快取?

對於喜歡java編程的人來說這相當於是一次練習。給你個提示,linkedhashmap可以用來實現固定大小的lru快取,當lru快取已經滿 了的時候,它會把最老的鍵值對移出快取。linkedhashmap提供了一個稱為removeeldestentry()的方法,該方法會被put() 和putall()調用來刪除最老的鍵值對。當然,如果你已經編寫了一個可運行的junit測試,你也可以隨意編寫你自己的實現代碼。

8. 你可以把list<string>傳遞給一個接受list<object>參數的方法嗎?

對任何一個不太熟悉泛型的人來說,這個java泛型題目看起來令人疑惑,因為乍看起來string是一種object,所以 list<string>應當可以用在需要list<object>的地方,但是事實並非如此。真這樣做的話會導致編譯錯誤。如 果你再深一步考慮,你會發現java這樣做是有意義的,因為list<object>可以存儲任何類型的對象包括string, integer等等,而list<string>卻只能用來存儲strings。

list<object> objectlist;

list<string> stringlist;

objectlist = stringlist; //compilation error incompatible types

9. array中可以用泛型嗎?

這可能是java泛型面試題中最簡單的一個了,當然前提是你要知道array事實上並不支持泛型,這也是為什麼joshua bloch在effective java一書中建議使用list來代替array,因為list可以提供編譯期的類型安全保證,而array卻不能。

10. 如何阻止java中的類型未檢查的警告?

如果你把泛型和原始類型混合起來使用,例如下列代碼,java 5的javac編譯器會產生類型未檢查的警告,例如

list<string> rawlist = new arraylist()

注意: hello.java使用了未檢查或稱為不安全的操作;

這種警告可以使用@suppresswarnings(“unchecked”)註解來禁止。

java泛型面試題補充更新:

我手頭又拿到了幾個java泛型面試題跟大家分享下,這幾道題集中在泛型類型和原始類型的區別上,以及我們是否可以用object來代替限定通配符的使用等等:

java中list<object>和原始類型list之間的區別?

原始類型和帶參數類型<object>之間的主要區別是,在編譯時編譯器不會對原始類型進行類型安全檢查,卻會對帶參數的類型進行檢 查,通過使用object作為類型,可以告知編譯器該方法可以接受任何類型的對象,比如string或integer。這道題的考察點在於對泛型中原始類 型的正確理解。它們之間的第二點區別是,你可以把任何帶參數的類型傳遞給原始類型list,但卻不能把list<string>傳遞給接受 list<object>的方法,因為會產生編譯錯誤。更多詳細信息請參閱java中的泛型是如何工作的。

java中list<?>和list<object>之間的區別是什麼?

這道題跟上一道題看起來很像,實質上卻完全不同。list<?> 是一個未知類型的list,而list<object> 其實是任意類型的list。你可以把list<string>, list<integer>賦值給list<?>,卻不能把list<string>賦值給 list<object>。     

list<?> listofanytype;

list<object> listofobject = new arraylist<object>();

list<string> listofstring = new arraylist<string>();

list<integer> listofinteger = new arraylist<integer>();

listofanytype = listofstring; //legal

listofanytype = listofinteger; //legal

listofobjecttype = (list<object>) listofstring; //compiler error – in-convertible types

想了解更多關於通配符的信息請查看java中的泛型通配符示例

list<string>和原始類型list之間的區別.

該題類似於“原始類型和帶參數類型之間有什麼區別”。帶參數類型是類型安全的,而且其類型安全是由編譯器保證的,但原始類型list卻不是類型安全 的。你不能把string之外的任何其它類型的object存入string類型的list中,而你可以把任何類型的對象存入原始list中。使用泛型的 帶參數類型你不需要進行類型轉換,但是對於原始類型,你則需要進行顯式的類型轉換。

list listofrawtypes = new arraylist();

listofrawtypes.add(“abc”);

listofrawtypes.add(123); //編譯器允許這樣 – 運行時卻會出現異常

string item = (string) listofrawtypes.get(0); //需要顯式的類型轉換

item = (string) listofrawtypes.get(1); //拋classcastexception,因為integer不能被轉換為string

list<string> listofstring = new arraylist();

listofstring.add(“abcd”);

listofstring.add(1234); //編譯錯誤,比在運行時拋異常要好

item = listofstring.get(0); //不需要顯式的類型轉換 – 編譯器自動轉換

這些都是java泛型面試中 頻繁出現的問題及其答案。所有這些面試題都不困難,其實它們都是基於泛型的基礎知識。任何對泛型有不錯了解的java程式設計師都肯定熟知這些泛型題目。如果 你有任何好的面試題,不管是在什麼面試中碰到的,或者如果你想知道任何java泛型面試題的答案。