热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c++list遍历_List集合就这么简单「源码剖析」

前言声明,本文用得是jdk1.8前一篇已经讲了Collection的总览:Collection总览,介绍了一些基础知识。现在这篇主要讲Li

前言

声明,本文用得是jdk1.8

前一篇已经讲了Collection的总览:Collection总览,介绍了一些基础知识。

现在这篇主要讲List集合的三个子类:

  • ArrayList
  • 底层数据结构是数组。线程不安全
  • LinkedList
  • 底层数据结构是链表。线程不安全
  • Vector
  • 底层数据结构是数组。线程安全

这篇主要来看看它们比较重要的方法是如何实现的,需要注意些什么,最后比较一下哪个时候用哪个~

看这篇文章之前最好是有点数据结构的基础:Java实现单向链表,栈和队列就是这么简单,二叉树就这么简单

e4e561601d3e23a682a1a6aab6972ec6.png
8993d4115433041062f59a68b143e8bf.png

当然了,如果讲得有错的地方还请大家多多包涵并不吝在评论去指正~

一、ArrayList解析

9c16d0421a911dff3695cd481b6cd7ac.png

首先,我们来讲解的是ArrayList集合,它是我们用得非常非常多的一个集合~

首先,我们来看一下ArrayList的属性:

cb64d7af30dcf08128b2372687bb907d.png

根据上面我们可以清晰的发现:ArrayList底层其实就是一个数组,ArrayList中有扩容这么一个概念,正因为它扩容,所以它能够实现“动态”增长

1.2构造方法

我们来看看构造方法来印证我们上面说得对不对:

b95a391996faed99f74748270e587dd9.png

1.3Add方法

add方法可以说是ArrayList比较重要的方法了,我们来总览一下:

571875cbe330ff2bb9192ad69c2fe7e1.png

1.3.1add(E e)

步骤:

  • 检查是否需要扩容
  • 插入元素

首先,我们来看看这个方法:

public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }

该方法很短,我们可以根据方法名就猜到他是干了什么:

  • 确认list容量,尝试容量加1,看看有无必要
  • 添加元素

接下来我们来看看这个小容量(+1)是否满足我们的需求:

b9b235cc0d47f481f15b631ae7736547.png

随后调用ensureExplicitCapacity()来确定明确的容量,我们也来看看这个方法是怎么实现的:

b3355306e691e63123fab7216960ab81.png

所以,接下来看看grow()是怎么实现的~

5c7a4b520a93008dc2bb7a3d6459aaf6.png

进去看copyOf()方法:

9e9aa64b0c1f0b9bf409a41393e5536e.png

到目前为止,我们就可以知道add(E e)的基本实现了:

  • 首先去检查一下数组的容量是否足够
  • 扩容到原来的1.5倍
  • 第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity。
  • 足够:直接添加
  • 不足够:扩容

1.3.2add(int index, E element)

步骤:

  • 检查角标
  • 空间检查,如果有需要进行扩容
  • 插入元素

我们来看看插入的实现:

520f449b57cb198eadc6109752e9a69a.png

我们发现,与扩容相关ArrayList的add方法底层其实都是arraycopy()来实现的

看到arraycopy(),我们可以发现:该方法是由C/C++来编写的,并不是由Java实现:

30831a31f275147cf2fbaa228bb1c464.png

总的来说:arraycopy()还是比较可靠高效的一个方法。

参考R大回答:https://www.zhihu.com/question/53749473

1.4 get方法

  • 检查角标
  • 返回元素
8b8dae18576dcff508a1c7de1bd702c6.png

// 检查角标 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } // 返回元素 E elementData(int index) { return (E) elementData[index]; }

1.5 set方法

步骤:

  • 检查角标
  • 替代元素
  • 返回旧值
0e46faf332f7c3285606ac6242705636.png

1.6remove方法

步骤:

  • 检查角标
  • 删除元素
  • 计算出需要移动的个数,并移动
  • 设置为null,让Gc回收
b59a426c45c2a822b43914428dac6659.png

1.7细节再说明

  • ArrayList是基于动态数组实现的,在增删时候,需要数组的拷贝复制
  • ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍
  • 删除元素时不会减少容量,若希望减少容量则调用trimToSize()
  • 它不是线程安全的。它能存放null值。
2511abe376a2eef49468c6d6d987a1d8.png

二、Vector与ArrayList区别

Vector是jdk1.2的类了,比较老旧的一个集合类。

19a4a8bf0fba636f88cd509b70c78aef.png

Vector底层也是数组,与ArrayList最大的区别就是:同步(线程安全)

Vector是同步的,我们可以从方法上就可以看得出来~

a0aa1d7a0f2471cb4e5959accd83726d.png

在要求非同步的情况下,我们一般都是使用ArrayList来替代Vector的了~

如果想要ArrayList实现同步,可以使用Collections的方法:List list = Collections.synchronizedList(new ArrayList(...));,就可以实现同步了~

还有另一个区别:

  • ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。
65e784a6efd930de81d752dfccc739b0.png
9d154b1aad9b3f3ce44f37cc767bef68.png

三、LinkedList解析

3db1cf8f765e25b7db8f6e721144eb44.png

LinkedList底层是双向链表~如果对于链表不熟悉的同学可先看看我的单向链表(双向链表的练习我还没做)

理解了单向链表,双向链表也就不难了。

da1cafdc838e5b244be3af5ba9bc5b7f.png

从结构上,我们还看到了LinkedList实现了Deque接口,因此,我们可以操作LinkedList像操作队列和栈一样~

0f0b715703595b8f000c1ea7f0132927.png

LinkedList变量就这么几个,因为我们操作单向链表的时候也发现了:有了头结点,其他的数据我们都可以获取得到了。(双向链表也同理)

9ab56f05e6918e5e3ff3837223bfdc3a.png

3.1构造方法

LinkedList的构造方法有两个:

4ad1347c6816d9e07a47ace63f6fd48b.png

3.2add方法

如果做过链表的练习,对于下面的代码并不陌生的~

  • add方法实际上就是往链表最后添加元素

public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Node l &#61; last; final Node newNode &#61; new Node<>(l, e, null); last &#61; newNode; if (l &#61;&#61; null) first &#61; newNode; else l.next &#61; newNode; size&#43;&#43;; modCount&#43;&#43;; }

3.3remove方法

9bff6b37f5b2afe9d53c96ec73163824.png
d09beb71ef3b260358590c771e6d0356.png

实际上就是下面那个图的操作&#xff1a;

fd6134e4592d20e84cdaaa5fcfc08b5b.png

3.4get方法

可以看到get方法实现就两段代码&#xff1a;

public E get(int index) { checkElementIndex(index); return node(index).item; }

我们进去看一下具体的实现是怎么样的&#xff1a;

b2fe24f84a2ef92ffc0ac73a164bde59.png

3.5set方法

set方法和get方法其实差不多&#xff0c;根据下标来判断是从头遍历还是从尾遍历

public E set(int index, E element) { checkElementIndex(index); Node x &#61; node(index); E oldVal &#61; x.item; x.item &#61; element; return oldVal; }


……LinkedList的方法比ArrayList的方法多太多了&#xff0c;这里我就不一一说明了。

四、总结

其实集合的源码看起来并不是很困难&#xff0c;遇到问题可以翻一翻&#xff0c;应该是能够看懂的~

ArrayList、LinkedList、Vector算是在面试题中比较常见的的知识点了。下面我就来做一个简单的总结&#xff1a;

ArrayList&#xff1a;

  • 底层实现是数组
  • ArrayList的默认初始化容量是10&#xff0c;每次扩容时候增加原先容量的一半&#xff0c;也就是变为原来的1.5倍
  • 增删时候&#xff0c;需要数组的拷贝复制(navite 方法由C/C&#43;&#43;实现)

LinkedList&#xff1a;

  • 底层实现是双向链表[双向链表方便实现往前遍历]

Vector&#xff1a;

  • 底层是数组&#xff0c;现在已少用&#xff0c;被ArrayList替代&#xff0c;原因有两个&#xff1a;
  • Vector所有方法都是同步&#xff0c;有性能损失
  • Vector初始length是10 超过length时 以100%比率增长&#xff0c;相比于ArrayList更多消耗内存
  • 参考资料&#xff1a;https://www.zhihu.com/question/31948523/answer/113357347

总的来说&#xff1a;查询多用ArrayList&#xff0c;增删多用LinkedList。

ArrayList增删慢不是绝对的(在数量大的情况下&#xff0c;已测试)&#xff1a;

  • 如果增加元素一直是使用add()(增加到末尾)的话&#xff0c;那是ArrayList要快
  • 一直删除末尾的元素也是ArrayList要快【不用复制移动位置】
  • 至于如果删除的是中间的位置的话&#xff0c;还是ArrayList要快&#xff01;

但一般来说&#xff1a;增删多还是用LinkedList&#xff0c;因为上面的情况是极端的~

原文来源&#xff1a;https://dwz.cn/R91iTN5B作者&#xff1a; Java3y


推荐阅读
  • 本文分析HashMap的实现原理。数据结构(散列表)HashMap是一个散列表(也叫哈希表),用来存储键值对( ... [详细]
  • 在这一期的SendMessage函数应用中,我将向大家介绍如何利用消息函数来扩展树型列表(TreeView)控件的功能相信对于树型列表控件大家十分的熟悉, ... [详细]
  • Shiro 简单了解
    Shiro简单了解简单用过SpringSecurity安全框架后,再试试另一个安全框架——Shiro。1.Shiro简介ApacheShiro是一个强大且易用的Java安全框架:S ... [详细]
  • C#按值复制数组我有一个类型化的数组MyType[]types;我想制作这个数组的独立副本。我试过这个MyType[]types2newMyType[types.Length];t ... [详细]
  • 互联网世界 9 种基本的商业模式
    互联网世界9种基本的商业模式一个商业模式是运行一个公司的方法;通过该模式的运作,一个公司能维持自己的生存,就是说,能有收益。商业模式意味着一个公司是如何通过在价值链中定位自己,从而获 ... [详细]
  • eecg的代码生成器很不错,但是可能有的时候不是那么符合我们实际项目的功能需求,这里会首先介绍jeecg原生生成的样子,以及根据需求进行的改造。Jeecg中的 ... [详细]
  • 1、概念共享内存:共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同malloc()函数向不同进程返回了指向同一个 ... [详细]
  • 我理解ViewHolder的onBindViewHolder如何工作,但是我不清楚notifyItemRangeChanged(0,this.data.size())如何;适用于此示例以及它的确 ... [详细]
  • [软件工具]最新最好最全的软件大全一起打包下载了[永远留种]
    软件下载列表:  安全防毒/QQ病毒专杀工具XPQQKav2006新春版.exe805.14KB  安全防毒/SymantecAntiVirus10. ... [详细]
  • DDOSDDOS的中文名叫分布式拒绝服务***,俗称洪水***DDoS***概念DoS的***方式有很多种,最基本的DoS***就是利用合理的服务请求来 ... [详细]
  • nvmw安装,用于控制node版本;
    之前一直使用的是nodev2.2.0版本,挺说新版本的node解决了npm安装插件产生文件夹结构过深的问题,所以就想更新试试;上网一看才发现,尼玛的node已经到了6.+版本了,好 ... [详细]
  • 第38天:Python decimal 模块
    by程序员野客在我们开发工作中浮点类型的使用还是比较普遍的,对于一些涉及资金金额的计算更是不能有丝毫误差,Python的decimal模块为浮点型精确计算提供了支持。1简介deci ... [详细]
  • 根据时间更改网站背景的脚本。热!
    我在网上找到了它,并以自己的方式对其进行了自定义;作者的功劳就在那里。实际上,这是一个用于更改背景颜色的脚本,并且在我看来& ... [详细]
  • IamusingmaterialDateTimepickerformyAndroidapp.ButIwanttocombinetheDateandTimepic ... [详细]
  • The“travellingsalesmanproblem”asksthefollowingquestion:“Givenalistofcitiesandthedistancesb ... [详细]
author-avatar
重羽玉婷018
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有