java泛型与迭代器的关系

简介: java泛型与迭代器的关系

泛型

  本质上是类型参数化,解决了不确定对象的类型问题。泛型的使用,参考下面代码:

ArrayList<String> arrayList = new ArrayList();
arrayList.add("Java");

泛型的优点

  • 安全:不用担心程序运行过程中出现类型转换的错误。
  • 避免了类型转换:如果是非泛型,获取到的元素是 Object 类型的,需要强制类型转换。
  • 可读性高:编码阶段就明确的知道集合中元素的类型。

迭代器(Iterator)

1.为什么要用迭代器?

在迭代器(Iterator)没有出现之前,如果要遍历数组和集合,需要使用方法。

数组遍历,代码如下:

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
}

总结:使用了迭代器就可以不用关注容器的内部细节,用同样的方式遍历不同类型的容器。

2.迭代器介绍

迭代器是用来遍历容器内所有元素对象的,也是一种常见的设计模式。包含以下四个方法。

  • hasNext():boolean —— 容器内是否还有可以访问的元素。
  • next():E —— 返回下一个元素。
  • remove():void —— 删除当前元素。
  • forEachRemaining(Consumer<? super E>):void —— JDK 8 中添加的,提供一个 lambda 表达式遍历容器元素。

3.迭代器使用

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));

笔试面试题

1.为什么迭代器的 next() 返回的是 Object 类型?

答:因为迭代器不需要关注容器的内部细节,所以 next() 返回 Object 类型就可以接收任何类型的对象。

2.HashMap 的遍历方式都有几种?

答:HashMap 的遍历分为以下四种方式。

  • 方式一:entrySet 遍历
  • 方式二:iterator 遍历
  • 方式三:遍历所有的 key 和 value
  • 方式四:通过 key 值遍历

以上方式的代码实现如下:

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 遍历  ,参考http://www.wityx.com/post/547_1_1.html
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));
}

3.以下关于泛型说法错误的是?

A:泛型可以修饰类

B:泛型可以修饰方法

C:泛型不可以修饰接口

D:以上说法全错

答:选 C,泛型可以修饰类、方法、接口、变量。

例如:

public interface Iterable<T> {
}

4.以下程序执行的结果是什么?

List<String> list = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list.getClass() == list2.getClass());

答:程序的执行结果是 true。

题目解析:Java 中泛型在编译时会进行类型擦除,因此 List<String> listList<Integer> list2 类型擦除后的结果都是 java.util.ArrayList ,进而 list.getClass() == list2.getClass() 的结果也一定是 true

5. List 和 List<?> 有什么区别?

答:List<?> 可以容纳任意类型,只不过 List<?> 被赋值之后,就不允许添加和修改操作了;而 List<Object> 在赋值之后,可以进行添加和修改操作.

参考http://www.wityx.com/post/547_1_1.html

6.可以把 List 赋值给 List 吗?

答:不可以,编译器会报错.

7. List 和 List 的区别是什么?

答: ListList<Object> 都能存储任意类型的数据,唯一区别是,List 不会触发编译器的类型安全检查,比如把 List<String> 赋值给 List 是没有任何问题的,但赋值给 List<Object> 就不行,

8.以下程序执行的结果是?

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Java虚拟机");
list.add("Java面试题网");
//http://www.wityx.com/post/539_1_1.html
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。

9.泛型的工作原理是什么?为什么要有类型擦除?

答:泛型是通过类型擦除来实现的,类型擦除指的是编译器在编译时,会擦除了所有类型相关的信息,比如 List 在编译后就会变成 List 类型,这样做的目的就是确保能和 Java 5 之前的版本(二进制类库)进行兼容。

相关文章
|
6天前
|
Java 编译器 容器
Java 泛型
Java 泛型
20 10
|
9天前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
16 3
Android面试题之Java 泛型和Kotlin泛型
|
2天前
|
存储 安全 Java
Java泛型(1)
Java泛型(1)
21 13
|
6天前
|
安全 Java 编译器
在Java中,什么是类型擦除机制,如何有效运用泛型的类型擦除机制?
Java的类型擦除机制在编译时移除了泛型的类型参数信息,生成的字节码不包含泛型,以确保向后兼容。这导致运行时无法直接获取泛型类型,但编译器仍做类型检查。为了有效利用类型擦除,应避免运行时类型检查,使用通配符和界限增加代码灵活性,通过超类型令牌获取泛型信息,以及利用泛型方法来保证安全性。理解这些策略能帮助开发者编写更安全的泛型代码。
29 8
|
8天前
|
安全 Java 开发者
Java泛型详解
Java泛型详解
15 2
|
15天前
|
存储 缓存 安全
Java基础15-深入理解Java中的泛型(二)
Java基础15-深入理解Java中的泛型(二)
16 4
|
13天前
|
安全 Java
深入理解 Java 泛型工厂方法:类型安全与灵活性的结合
深入理解 Java 泛型工厂方法:类型安全与灵活性的结合
10 1
|
13天前
|
安全 Java 编译器
Java 泛型详解:全面掌握类型安全与灵活性的利器
Java 泛型详解:全面掌握类型安全与灵活性的利器
13 1
|
13天前
|
安全 Java 开发者
详解 Java 泛型:核心概念与实用示例
详解 Java 泛型:核心概念与实用示例
11 1
|
22天前
|
存储 安全 Java
【Java基础】 泛型编程
Java泛型是一种通过参数化类型提升代码复用性和安全性的编程方式,允许在类、接口和方法中使用类型参数。泛型类如`Box&lt;T&gt;`可在实例化时指定类型,泛型方法如`&lt;T&gt; void printArray(T[] array)`在方法声明中指定类型参数。类型通配符如`?`用于增强灵活性,`? extends T`表示类型为T或其子类,`? super T`则为T或其父类。类型擦除保证泛型不增加运行时开销,但会导致某些限制。示例展示了泛型类、方法和无界通配符的综合运用。
20 4