Collection Framework的Iterator实现,2024历年华为跳动Android面试真题解析

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException ex) {

throw new ConcurrentModificationException();

}

}

final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

}

ItrArrayList的一个内部类,它能使用宿主类的成员变量,事实上Itr反映了ArrayList的内部情况,使用了sizeexpectedModCountelementData等属性。通过游标cursor的方式不断往前递进,只要游标小于size就说明依然还有元素可以访问。

应该看到的是,在调用了new Iterator()之后,可以看做ItrArrayList做了快照,这里的快照并不是很严格,是基于modCount比较来实现的。它在初始化时备份了modCount的值,保存为私有的变量expectedModCount

首先Iterator接口并没有诸如add的方法,即不能通过Iterator来为容器增加元素;

其次,如果有其他线程变化了容器的结构(structural modification),那么ArrayList.this.modCount的值会发生改变,那么在Itr执行next或者remove方法时会判断出来modCount != expectedModCount的情况,从而抛出异常fast-fail

再次,如果执行了Itr的remove方法,它能够调用ArrayList.this.remove的方法,然后修正游标和expectedModCount等。

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

2)LinkedList中的Iterator

LinkedListIteratorArrayList中的有一些类似的地方。

首先,LinkedList的iterator入口方法其实是AbstractSequentialList抽象类中,

/**

  • Returns an iterator over the elements in this list (in proper

  • sequence).

  • This implementation merely returns a list iterator over the list.

  • @return an iterator over the elements in this list (in proper sequence)

*/

public Iterator iterator() {

return listIterator();

}

/**

  • Returns a list iterator over the elements in this list (in proper

  • sequence).

  • @param index index of first element to be returned from the list

  •     iterator (by a call to the <code>next</code> method)
    
  • @return a list iterator over the elements in this list (in proper

  •     sequence)
    
  • @throws IndexOutOfBoundsException {@inheritDoc}

*/

public abstract ListIterator listIterator(int index);

而这个ListIterator是一个接口,它被LinkedList$ListItr实现,

private class ListItr implements ListIterator {

private Node lastReturned = null;

private Node next;

private int nextIndex;

private int expectedModCount = modCount;

ListItr(int index) {

// assert isPositionIndex(index);

next = (index == size) ? null : node(index);

nextIndex = index;

}

public boolean hasNext() {

return nextIndex < size;

}

public E next() {

checkForComodification();

if (!hasNext())

throw new NoSuchElementException();

lastReturned = next;

next = next.next;

nextIndex++;

return lastReturned.item;

}

public boolean hasPrevious() {

return nextIndex > 0;

}

public E previous() {

checkForComodification();

if (!hasPrevious())

throw new NoSuchElementException();

lastReturned = next = (next == null) ? last : next.prev;

nextIndex–;

return lastReturned.item;

}

public int nextIndex() {

return nextIndex;

}

public int previousIndex() {

return nextIndex - 1;

}

public void remove() {

checkForComodification();

if (lastReturned == null)

throw new IllegalStateException();

Node lastNext = lastReturned.next;

unlink(lastReturned);

if (next == lastReturned)

next = lastNext;

else

nextIndex–;

lastReturned = null;

expectedModCount++;

}

public void set(E e) {

if (lastReturned == null)

throw new IllegalStateException();

checkForComodification();

lastReturned.item = e;

}

public void add(E e) {

checkForComodification();

lastReturned = null;

if (next == null)

linkLast(e);

else

linkBefore(e, next);

nextIndex++;

expectedModCount++;

}

final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

}

LinkedListIterator要比ArrayList中的复杂一些,它更支持了add等方法;

类似原来游标的遍历方式,基于sizeexpectedModCount等比较逻辑依然存在,只不过遍历的方式不是原来的下标增进,而是节点之间的next指针来实现。

3)HashMap中的Iterator

HashMap有多个view视图,keySetvaluesentrySet,这里分析下entrySet这个视图,另外两个原理和entrySet视图的差不多。

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {

public Iterator<Map.Entry<K,V>> iterator() {

return newEntryIterator();

}

public boolean contains(Object o) {

if (!(o instanceof Map.Entry))

return false;

Map.Entry<K,V> e = (Map.Entry<K,V>) o;

Entry<K,V> candidate = getEntry(e.getKey());

return candidate != null && candidate.equals(e);

}

public boolean remove(Object o) {

return removeMapping(o) != null;

}

public int size() {

return size;

}

public void clear() {

HashMap.this.clear();

}

}

EntrySet的iterator方法中调用了newEntryIterator,将构造EntryIterator实例,

EntryIterator源码

private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {

public Map.Entry<K,V> next() {

return nextEntry();

}

}

EntryIterator继承了HashIterator类,复用了父类的大部分方法,只是覆盖了next方法。

HashIterator源码,

private abstract class HashIterator implements Iterator {

Entry<K,V> next; // next entry to return

int expectedModCount; // For fast-fail

int index; // current slot

Entry<K,V> current; // current entry

HashIterator() {

expectedModCount = modCount;

if (size > 0) { // advance to first entry

Entry[] t = table;

while (index < t.length && (next = t[index++]) == null)

;

}

}

public final boolean hasNext() {

return next != null;

}

final Entry<K,V> nextEntry() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

Entry<K,V> e = next;

if (e == null)

throw new NoSuchElementException();

if ((next = e.next) == null) {

Entry[] t = table;

while (index < t.length && (next = t[index++]) == null)

;

}

current = e;

return e;

}

public void remove() {

if (current == null)

throw new IllegalStateException();

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

Object k = current.key;

current = null;

HashMap.this.removeEntryForKey(k);

expectedModCount = modCount;

}

}

由于HashMap的结构并不是顺序的,在执行Iterator.next方法时不能通过next指针或下标的方式直接找到下一个元素,HashIterator为了能达到这个目的,在构造函数和nextEntry方法中预先做了advance处理。

//构造函数中

if (size > 0) { // advance to first entry

Entry[] t = table;

while (index < t.length && (next = t[index++]) == null)

;

}

//nextEntry中

if ((next = e.next) == null) {

Entry[] t = table;

while (index < t.length && (next = t[index++]) == null)

;

}

构造函数中预先在HashMap的table数组找到第一个头结点不为null的元素;

(next = t[index++]) == null的写法有点迷惑性,不考虑HashMap为空的情况,index自增停在next != null的情况,即 next = t[index-1], index已经往前一步了;

在nextEntry中如果发现e.next是null,此时表示table这个数组元素的链表遍历结束了,需要跳到下一个头节点不为空的元素继续遍历,而index刚好往前一步了,此时继续执行

next = t[index++]

假设next[index]不为空,那么下一个遍历的数组元素头节点找到,并且index已经自增了。

并发数据结构的情况


ConcurrentHashMap为例,看ConcurrentHashMap$HashInteraotr的实现

abstract class HashIterator {

int nextSegmentIndex;

int nextTableIndex;

HashEntry<K,V>[] currentTable;

HashEntry<K, V> nextEntry;

HashEntry<K, V> lastReturned;

HashIterator() {

nextSegmentIndex = segments.length - 1;

nextTableIndex = -1;

advance();

}

/**

  • Set nextEntry to first node of next non-empty table

  • (in backwards order, to simplify checks).

*/

final void advance() {

for (;😉 {

if (nextTableIndex >= 0) {

if ((nextEntry = entryAt(currentTable,

nextTableIndex–)) != null)

break;

}

else if (nextSegmentIndex >= 0) {

Segment<K,V> seg = segmentAt(segments, nextSegmentIndex–);

if (seg != null && (currentTable = seg.table) != null)

nextTableIndex = currentTable.length - 1;

}

else

break;

}

}

final HashEntry<K,V> nextEntry() {

HashEntry<K,V> e = nextEntry;

if (e == null)

throw new NoSuchElementException();

lastReturned = e; // cannot assign until after null check

if ((nextEntry = e.next) == null)

advance();

return e;

}

public final boolean hasNext() { return nextEntry != null; }

public final boolean hasMoreElements() { return nextEntry != null; }

public final void remove() {

if (lastReturned == null)

throw new IllegalStateException();

ConcurrentHashMap.this.remove(lastReturned.key);

lastReturned = null;

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

Android开发8年,阿里、百度一面惨被吊打!我是否应该转行了?

【Android进阶学习视频】、【全套Android面试秘籍】

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多程序员朋友无法获得正确的资料得到学习提升,故此将并将重要的Android进阶资料包括自定义view、性能优化、MVC与MVP与MVVM三大框架的区别、NDK技术、阿里面试题精编汇总、常见源码分析等学习资料。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-4etiTjC0-1712484245227)]

【Android进阶学习视频】、【全套Android面试秘籍】

希望我能够用我的力量帮助更多迷茫、困惑的朋友们,帮助大家在IT道路上学习和发展

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 26
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值