在泛型没有诞生以前,咱们常常会遇到这样的问题,如如下代码所示: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” ,将会有大礼相送!!! 祝各位面试成功!!!】