在泛型沒有誕生以前,咱們常常會遇到這樣的問題,如如下代碼所示:java
ArrayList arrayList = new ArrayList(); arrayList.add("Java"); arrayList.add(24); for (int i = 0; i < arrayList.size(); i++) { String str = (String) arrayList.get(i); System.out.println(str); }
看起來好像沒有什麼大問題,也能正常編譯,但真正運行起來就會報錯:面試
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat xxx(xxx.java:12)設計模式
類型轉換出錯,當咱們給 ArrayList 放入不一樣類型的數據,卻使用一種類型進行接收的時候,就會出現不少相似的錯誤,可能更多的時候,是由於開發人員的不當心致使的。那有沒有好的辦法能夠杜絕此類問題的發生呢?這個時候 Java 語言提供了一個很好的解決方案——「泛型」。數組
泛型:泛型本質上是類型參數化,解決了不肯定對象的類型問題。
泛型的使用,請參考如下代碼:安全
ArrayList<String> arrayList = new ArrayList(); arrayList.add("Java");
這個時候若是給 arrayList 添加非 String 類型的元素,編譯器就會報錯,提醒開發人員插入相同類型的元素。編碼
這樣就能夠避免開頭示例中,類型不一致致使程序運行過程當中報錯的問題了。spa
泛型的優勢主要體如今如下三個方面。設計
咱們回想一下,在迭代器(Iterator)沒有出現以前,若是要遍歷數組和集合,須要使用方法。code
數組遍歷,代碼以下:對象
String[] arr = new String[]{"Java", "Java虛擬機", "Java中文社羣"}; for (int i = 0; i < arr.length; i++) { String item = arr[i]; }
集合遍歷,代碼以下:
List<String> list = new ArrayList<String>() {{ add("Java"); add("Java虛擬機"); add("Java中文社羣"); }}; for (int i = 0; i < list.size(); i++) { String item = list.get(i); }
而迭代器的產生,就是爲不一樣類型的容器遍歷,提供標準統一的方法。
迭代器遍歷,代碼以下:
Iterator iterator = list.iterator(); while (iterator.hasNext()) { Object object = iterator.next(); // do something }
總結:使用了迭代器就能夠不用關注容器的內部細節,用一樣的方式遍歷不一樣類型的容器。
迭代器是用來遍歷容器內全部元素對象的,也是一種常見的設計模式。
迭代器包含如下四個方法。
迭代器使用以下:
List<String> list = new ArrayList<String>() {{ add("Java"); add("Java虛擬機"); add("Java中文社羣"); }}; Iterator iterator = list.iterator(); // 遍歷 while (iterator.hasNext()){ String str = (String) iterator.next(); if (str.equals("Java中文社羣")){ iterator.remove(); } } System.out.println(list);
程序執行結果:
[Java, Java虛擬機]
forEachRemaining 使用以下:
List<String> list = new ArrayList<String>() {{ add("Java"); add("Java虛擬機"); add("Java中文社羣"); }}; // forEachRemaining 使用 list.iterator().forEachRemaining(item -> System.out.println(item));
答:由於迭代器不須要關注容器的內部細節,因此 next() 返回 Object 類型就能夠接收任何類型的對象。
答:HashMap 的遍歷分爲如下四種方式。
以上方式的代碼實現以下:
Map<String, String> hashMap = new HashMap(); hashMap.put("name", "老王"); hashMap.put("sex", "你猜"); // 方式一:entrySet 遍歷 for (Map.Entry item : hashMap.entrySet()) { System.out.println(item.getKey() + ":" + item.getValue()); } // 方式二:iterator 遍歷 Iterator<Map.Entry<String, String>> iterator = hashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); System.out.println(entry.getKey() + ":" + entry.getValue()); } // 方式三:遍歷全部的 key 和 value for (Object k : hashMap.keySet()) { // 循環全部的 key System.out.println(k); } for (Object v : hashMap.values()) { // 循環全部的值 System.out.println(v); } // 方式四:經過 key 值遍歷 for (Object k : hashMap.keySet()) { System.out.println(k + ":" + hashMap.get(k)); }
A:泛型能夠修飾類
B:泛型能夠修飾方法
C:泛型不能夠修飾接口
D:以上說法全錯
答:選 C,泛型能夠修飾類、方法、接口、變量。
例如:
public interface Iterable\<T\> { }
List<String> list = new ArrayList<>(); List<Integer> list2 = new ArrayList<>(); System.out.println(list.getClass() == list2.getClass());
答:程序的執行結果是 true
。
題目解析:Java 中泛型在編譯時會進行類型擦除,所以 List<String> list
和 List<Integer> list2
類型擦除後的結果都是 java.util.ArrayLis ,進而 list.getClass() == list2.getClass() 的結果也必定是 true。
List<Object>
和 List<?>
有什麼區別?答:List<?>
能夠容納任意類型,只不過 List<?>
被賦值以後,就不容許添加和修改操做了;而 List<Object>
和 List<?>
不一樣的是它在賦值以後,能夠進行添加和修改操做,以下圖所示:
6.能夠把 List<String>
賦值給 List<Object>
嗎?
答:不能夠,編譯器會報錯,以下圖所示:
List 和 List<Object>
的區別是什麼?
答: List
和 List<Object>
都能存儲任意類型的數據,但 List
和 List<Object>
的惟一區別就是,List
不會觸發編譯器的類型安全檢查,好比把 List<String>
賦值給 List
是沒有任何問題的,但賦值給 List<Object>
就不行,以下圖所示:
List<String> list = new ArrayList<>(); list.add("Java"); list.add("Java虛擬機"); list.add("Java中文社羣"); Iterator iterator = list.iterator(); while (iterator.hasNext()) { String str = (String) iterator.next(); if (str.equals("Java中文社羣")) { iterator.remove(); } } while (iterator.hasNext()) { System.out.println(iterator.next()); } System.out.println("Over");
答:程序打印結果是 Over
。
題目解析:由於第一個 while 循環以後,iterator.hasNext() 返回值就爲 false 了,因此不會進入第二個循環,以後打印最後的 Over。
答:泛型是經過類型擦除來實現的,類型擦除指的是編譯器在編譯時,會擦除了全部類型相關的信息,好比 List<String>
在編譯後就會變成 List
類型,這樣作的目的就是確保能和 Java 5 以前的版本(二進制類庫)進行兼容。
經過本文知道了泛型的優勢:安全性、避免類型轉換、提升了代碼的可讀性。泛型的本質是類型參數化,但編譯以後會執行類型擦除,這樣就能夠和 Java 5 以前的二進制類庫進行兼容。本文也介紹了迭代器(Iterator)的使用,使用迭代器的好處是不用關注容器的內部細節,用一樣的方式遍歷不一樣類型的容器。
_
歡迎關注個人公衆號,回覆關鍵字「Java」 ,將會有大禮相送!!! 祝各位面試成功!!!
】