1.海康威视一面:Iterator与Iterable有什么区别?
2.List 删除使用Iterator迭代器
3.STL源码剖析总结笔记(5):认识迭代器的源码好帮手--list
海康威视一面:Iterator与Iterable有什么区别?
在海康威视面试中,面试官老王问了小二一个常见问题:Iterator与Iterable有什么区别?
一年前,源码小二在《Java程序员进阶之路》专栏上第篇已经遇到过这个问题。源码
在Java中,源码遍历List主要有三种方式:for循环、源码迭代器和for-each。源码丰源源码
for-each其实是源码语法糖,背后也是源码迭代器。
迭代器是源码一个接口,自1.2版本出现,源码用来改进枚举。源码
Iterable接口在JDK1.8中新增了forEach方法,源码用于对集合元素执行指定操作。源码
如果我们仔细观察ArrayList或LinkedList的源码“户口本”,没有直接找到迭代器,源码业务网源码2019反而找到了Iterable。
这说明List关系图谱中并未直接使用迭代器,而是通过Iterable过渡。
再看第二种遍历List方式,正好呼应了Iterable的iterator方法。
对于Map,无法直接使用for-each,因为Map未实现Iterable接口。
LinkedList并未直接重写Iterable接口的iterator方法,而是由其父类AbstractSequentialList完成。
LinkedList重写了listIterator方法,使用了新的迭代器ListIterator,支持双向遍历。
虽然迭代器支持List和Set,断网报警源码但ListIterator只支持List。
对于List实现,使用迭代器可以有多种遍历方式,如正序和逆序。
总结,Iterator和Iterable主要区别在于,前者定义了迭代的接口,后者定义了支持迭代的集合。
《Java程序员进阶之路》专栏内容丰富,适合Java初学者,包括Java语法、集合框架、IO、并发编程、梦想逍遥650源码虚拟机等核心知识点。
List 删除使用Iterator迭代器
在处理列表(List)中的元素时,使用迭代器(Iterator)是一种非常常见的方法。Iterator可以遍历集合中的元素,实现元素的增删改查操作。Iterator有多种方法,其中包括next()、hasNext()、remove()等。以ArrayList为例,以下代码展示了如何使用Iterator遍历并删除列表中的元素。
代码如下:
java
List list = new ArrayList>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add("F");
list.add("G");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (element.equals("C")) {
iterator.remove();
}
}
运行结果显示:A,B,D,单向好友api源码E,F,G,已删除元素C。
在处理List中的元素时,我们通常会使用ListIterator。ListIterator与普通的Iterator相比,多了一些特殊的方法,如add()、set()等,这些方法允许我们在遍历的同时插入或修改元素。以下是使用ListIterator的代码示例:
java
List list = new ArrayList>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add("F");
list.add("G");
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()) {
String element = listIterator.next();
if (element.equals("C")) {
listIterator.set("C修改后的值");
listIterator.add("插入的元素");
}
}
运行结果展示:A,B,C修改后的值,D,E,F,G,已插入元素和修改元素。
Iterator与ListIterator的主要区别在于,ListIterator提供了对元素的增删改查操作,而Iterator只能用于遍历元素。在进行复杂操作时,使用ListIterator能够更加方便地处理列表元素。
STL源码剖析总结笔记(5):认识迭代器的好帮手--list
在深入探讨STL中的`list`容器之前,我们先简要回顾了`vector`的特性以及分配器(`allocator`)的作用。接下来,我们将转向一个具有代表性的容器——`list`。之所以说其具有代表性,是因为`list`利用非连续的空间存储元素,从而在空间利用上更为精确。学习`list`是掌握迭代器机制的第一步。
“list”实质上是双向链表,它具有两个重要特性:前向指针和后向指针。在STL中,`list`节点的定义可能使用`_list_node*`(可能为了兼容性或设计规范)来指代节点结构,其中包含了指向下一个节点和上一个节点的指针。
`list`的内部实现为一个环状的双向链表结构,通过一个指向虚拟尾节点的指针`node`来方便遍历。`begin()`和`end()`方法的实现依赖于这个`node`。此外,`empty()`、`size()`、`front()`(访问头节点内容)、`back()`(访问尾节点内容)等方法的实现相对直截了当。
`list`的迭代器(`iterator`)设计得更为复杂,因为非连续的空间分配使得简单指针的操作无法直接使用。迭代器需要智能地追踪当前节点及其前后的节点,以便进行递增、递减和取值操作。这要求迭代器实现诸如`++`和`--`等操作符的重载,同时还需要定义至少1-5个`typedef`类型来支持迭代器的基本行为。
`++`操作符的重载遵循前置`++`和后置`++`的区别:前置`++`直接返回计算后的结果(即更新后的迭代器),而后置`++`返回迭代器的副本,避免了在C++中直接对整数进行两次后置`++`的操作,因为这会导致未定义的行为。`*`和`->`操作符用于访问当前节点的数据和成员,后者通过`*`操作符访问节点数据后再通过指针访问成员,确保了数据的安全访问。
`list`的基本操作主要依赖于节点指针的移动和修改,如插入、删除等。这些操作通常需要考虑双向链表的特性以及虚拟尾节点的存在,以避免丢失数据或产生无效指针。例如,`transfer()`方法是一个关键功能,允许将一段连续范围的元素移动到链表中的特定位置,这是许多其他复杂操作的基础。
在`list`中,`transfer()`方法实现了将`[first,last)`范围内的元素移动到指定位置的逻辑,通过调整节点的`next`和`prev`指针来完成移动,同时确保了数据的完整性。基于`transfer()`方法,其他高级操作也能够实现,尽管这些操作通常不直接暴露给用户,而是通过封装在`list`内部的实现来提供。
学习`list`不仅有助于理解迭代器的设计原理,也为探索其他容器(如`vector`和`deque`)的实现提供了基础。在接下来的内容中,我们将详细探讨迭代器的实现技巧,以及如何在实际编程中利用这些概念来优化代码。