JDK源码学习之Arraylist与LinkedList

ArrayList和LinkedList是我们在开发过程中常用的两种集合类,本文将从底层源码实现对其进行简单介绍。

下图是Java集合类所涉及的类图。

JDK源码学习之Arraylist与LinkedList

一.ArrayList

从上面的集合类图可以看出,ArrayList实现了List接口。ArrayList是顺序的集合容器,容器中可以存放null元素,而底层则是通过一个可自动增长大小的动态数组实现的。ArrayList不是线程安全的,也没有实现同步。

1.1 ArrayList操作性能

访问数组中第 n 个数据的时间花费是 O(1),但是要在数组中查找一个指定的数据则是 O(N)。当向数组中插入或者删除数据的时候,最好的情况是在数组的末尾进行操作,时间复杂度是 O(1),但是最坏情况是插入或者删除第一个数据,时间复杂度是O(N)。在数组的任意位置插入或者删除数据的时候,后面的数据全部需要移动,移动的数据还是和数据个数有关所以总体的时间复杂度仍然是O(N)。

JDK源码学习之Arraylist与LinkedList

1.2 私有属性

ArrayList有两个私有属性,一个是实现数据存储的数组,一个是表示数组中元素的个数。值得注意的是关键字transient。

JDK源码学习之Arraylist与LinkedList

ArrayList这个类实现了Serializable接口。Java的Serializable提供了一种持久化对象实例的机制,当持久化对象时,可能某个特殊的对象数据成员我们不想让其用Serializable机制保存它,可以使用关键字transient来进行屏蔽。此外还有个保护的属性:modCount,含义为已从结构上修改此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。

1.3 构造方法

ArrayList中有三个构造函数,一个是默认构造一个容量为10的数组,一个指定容量的空列表和一个Collection类型的空列表。我们可以在使用时通过指定我们预估到的数组容量,来减少扩容次数

1.4 数组扩容

每一个ArrayList的实例都有一个容量,用来表示存储数据的数组大小。容器内的元素不能大于当前当前的容器大小。当向容器中添加数据时,若容器的容量不足,容器会自动扩容。通过对比jdk1.7的ArrayList源码发现,扩容两个方法是不一样的,jdk1.6中使用的是除法对其容量进行计算(加0.5倍),而jdk1.7中则使用的是移运算。

JDK源码学习之Arraylist与LinkedList

位运算是CPU直接操作的,除法等四则运算都是基于移位运算的,所以当有大量计算的时候,移位运算可以大大节约CPU的时间。通过1千万次位运算和四则运算做对比数据结果如下:

JDK源码学习之Arraylist与LinkedList

可以看出,在计算大量数据的情况下,移位运算的花费时间比乘除法快很多。

1.5 数组复制方法

JDK源码学习之Arraylist与LinkedList

可以看到在ensureCapacity(intminCapacity)中调用的是Arrays的copyOf()方法,而在add方法中,调用的数组复制方法为:

native void arraycopy();Arrays的copyOf方法的实现:

JDK源码学习之Arraylist与LinkedList

实现copyOf的时候会新创建一个大小为newCapcity的数组,然后将旧的elementData放入其中。

1.6 小节

1、通过查看ArrayList的源码,注意到有三个不同的构造方法,合理使用构造方法能减少数组扩容拷贝造成的额外开销。

2、ArrayList大量调用了Arrays.copyOf和System.arrayCopy的方法,注意这两个方法的区别。

3、jdk1.6和1.7中数组扩容的方法不一致,注意比较有差异的地方。

二.LinkedList

LinkedList与ArrayList一样实现List接口,只是ArrayList是List接口的大小可变数组的实现,LinkedList是List接口链表的实现。基于链表实现的方式使得LinkedList在插入和删除时更优于ArrayList,而随机访问则比ArrayList逊色些。

除了实现 List 接口外,LinkedList类还实现 Deque接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。

LinkedList定义:

public class LinkedList<E > extends AbstractSequentialList<E>

implements List<E>,Deque<E>, Cloneable, java.io.Serializable

2.1 底层数据结构

与ArrayList的区别在于,LinkedList底层是基于双向链表实现的:

以上的数据结构可以从LinkedList的私有属性看出:

private transient Entry<E> header = newEntry<E>(null, null, null);//头结点是不存放元素的

private transient int size = 0;//双向循环链表的大小

2.2 双向循环列表的操作性能

对于双向循环链表的插入和删除操作只是多移动几个指针。

备注:这里只是单纯的描述双向链表这种数据结构的插入和删除性能,下文将对比ArrayList与LinkedList的性能。

2.3 构造函数

LinkedList类有两个构造函数,一个是无参数的,一个是构造任意类型的集合类的列表

该构造函数构造一个空的列表,header头结点表示如下, 形成一个闭环。

有参构造方法,参数为collection的c,this()调用默认的无参构造函数,然后再调用addAll()方法,将c中的元素添加加入列表。

三.LinkedList与ArrayList比较

1.ArrayList是基于数组的数据结构,LinkedList是基于链表的数据结构。

2.ArrayList内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组.但LinkedList在get与set方面弱于ArrayList.

当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义.

3.此外 LinkedList 还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll()等.

注意: 默认情况下ArrayList的初始容量非常小,所以如果可以预估数据量的话,分配一个较大的初始值属于最佳实践,这样可以减少调整大小的开销。

4.对于ArrayList与LinkedList性能下图做个简单比较

* 表中的 add() 代表 add(E e),而 remove()代表 remove(int index)

ArrayList 对于随机位置的add/remove,时间复杂度为 O(n),但是对于列表末尾的添加/删除操作,时间复杂度是 O(1). 而LinkedList对于随机位置的add/remove,时间复杂度为 O(n),但是对于列表 末尾/开头 的添加/删除操作,时间复杂度是 O(1).

下面是测试代码:

JDK源码学习之Arraylist与LinkedList

输出结果截图如下:

JDK源码学习之Arraylist与LinkedList

上述测试可以看出LinkedList在 进行add和remove操作时更快,而在进行get操作时较慢.

通过本次源码学习之旅,我从LinkedList、ArrayList的底层结构出发,更深刻地了解了这两个类的一些基本操作方法,文章中有不周全的地方欢迎指正,共同学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习记录4

学习了python基本数据类型&#xff0c;附学习笔记图及操作图 转载于:https://www.cnblogs.com/bgd140206127/p/6549229.html

Java开发必须熟悉的Linux命令总结

身为一个Java开发人员&#xff0c;这些常用的Linux命令必须掌握。即使平时开发过程中没有使用Linux&#xff08;Unix&#xff09;或者mac系统&#xff0c;也需要熟练掌握Linux命令。因为很多服务器上都是Linux系统。所以&#xff0c;要和服务器机器交互&#xff0c;就要通过she…

kettle-实现每个分组的前N的数据

2019独角兽企业重金招聘Python工程师标准>>> 第一步&#xff1a;创建表及数据&#xff1a; create table uid(uid int, --uidcate varchar(20), --类别price double --金额 ) insert into uid values(123,c1,21); insert into uid values(123,c2,23); insert into u…

linux nexus 使用问题

2019独角兽企业重金招聘Python工程师标准>>> 问题一&#xff0c;启动提示设置RUN_AS_USERroot 但是&#xff0c;设置export或 /etc/profile未生效。 **************************************** WARNING - NOT RECOMMENDED TO RUN AS ROOT *************************…

项目回顾-PopupWindow

右上菜单&#xff0c;可以通过 重写 onCreateOptionsMenu指定 menu&#xff0c; 重写 onOptionsItemSelected 来响应点击事件 不过 这个菜单在某些手机上弹出的有点卡顿&#xff0c;而且如果不对主题进行设置&#xff0c;会从actionbar 上直接弹出&#xff0c;而不是下面 如果想…

qt android glsl,基于Qt的OpenGL学习(1)—— Hello Triangle

简介要学习OpenGL的话&#xff0c;强烈安利这个教程JoeyDeVries的learnopengl&#xff0c;这里是中文翻译好的版本。教程中使用OpenGL是通过GLFW这个库&#xff0c;而在Qt中对OpenGL封装得很好&#xff0c;并且和GUI以及IO相关的处理Qt更便捷&#xff0c;学习起来更轻松。这里就…

解决:Not Found: /favicon.ico

直接说解决办法&#xff1a; &#xff08;1&#xff09;制作一个 favicon.ico图标放在<head></head>标签中 <link rel"shortcut icon" href"xxxxxxxxxx.ico" type"image/x-icon" /> <!--制作的图标&#xff0c;使用hr…

多态方法调用的解析和分派

方法调用并不等同于方法执行&#xff0c;方法调用阶段唯一的任务就是确定被调用方法的版本&#xff08;即调用哪一个方法&#xff09;&#xff0c;暂时还不涉及方法内部的具体运行过程。在程序运行时&#xff0c;进行方法调用是最普遍、最频繁的操作&#xff0c;Class文件的编译…

关于用VS写C程序运行时出现烫字以及乱码的问题的原因

最近在复习C语言写程序时&#xff0c;突然碰到标题上的这种情况&#xff0c;后来经过上网查找以及逐步调试才发现原来是在打印数组的时候“越界”导致的&#xff0c;因为程序在默认初始化char类型的数组时&#xff0c;初始化的值是“烫”字&#xff0c;一般情况下是字符串未初始…

ARM TK1 安装kinect驱动

首先安装usb库 $ git clone https://github.com/libusb/libusb.git 编译libusb需要的工具 $ sudo apt-get install autoconf autogen $ sudo apt-get install libtool $ sudo apt-get install libudev* 编译安装 $ sudo ./autogen.sh $ sudo make $ sudo make install $ sudo l…

大数据入门:各种大数据技术的介绍

大数据我们都知道hadoop&#xff0c;可是还会各种各样的技术进入我们的视野&#xff1a;Spark&#xff0c;Storm&#xff0c;impala&#xff0c;让我们都反映不过来。为了能够更好的架构大数据项目&#xff0c;这里整理一下&#xff0c;供技术人员&#xff0c;项目经理&#xf…

安装安全类软件进行了android签名漏洞修补,魅族MX3怎么升级固件体验最新比较稳定的版本...

魅族mx3固件怎么升级?flyme os系统会持续更新&#xff0c;升级魅族MX3手机系统需先下载MX3的升级固件&#xff0c;升级固件分为体验版和稳定版。魅族MX3固件有体验版和稳定版两种&#xff0c;顾名思义&#xff0c;体验版为最新版但相比稳定版来说存在更多的漏洞&#xff0c;升…

ubuntu入门知识

1、linux系统发展历史 unix -> Linux -> ubuntu linux发展轨迹图 2、ubuntu下载和安装 推荐使用长期支持版本&#xff1a; 10.04,12.04,14.04或LTS版本 安装环境VMware虚拟机 3、安装之后创建root sudo passwd root 输入root用户密码即可 4、安装软件&#xff1a; 更新软…

Vim的基本操作总结

最近在学习Linux基础的时候&#xff0c;对Vim的基本操作时遇到很多问题&#xff0c;如编辑错误&#xff0c;无法退出Vim等。通过一系列的学习后才解决了这些问题&#xff0c;希望这个过程能对后来者有所帮助 先对Vim的三种模式做个大致的介绍&#xff1a; Vi有三种基本工作模式…

11月14号站立会议(从即日14号起到24号截至为final阶段工作期)

小组名称&#xff1a;飞天小女警 项目名称&#xff1a;礼物挑选小工具 小组成员&#xff1a;沈柏杉&#xff08;组长&#xff09;、程媛媛、杨钰宁、谭力铭 代码地址&#xff1a;HTTPS:https://git.coding.net/shenbaishan/GIFT.git SSH&#xff1a;gitgit.coding.net:shenbais…

初学大数据之模块集成:Pycharm安装numpy,scipy,sklearn等包时遇到的各种问题的一键解决方法

最近在学习机器学习&#xff0c;要用Python写程序&#xff0c;习惯了用IDE软件&#xff0c;所以就使用Pycharm软件。但是在导入类似numpy,sklearn等模块的时候&#xff0c;发现了各种问题&#xff08;如Python版本与模块之间的兼容等各类问题&#xff09;,上网找了许多方法&…

html 圆环实现多种颜色,SVG实现多彩圆环倒计时效果的示例代码

圆环倒计时我们经常见到&#xff0c;实现的方法也有很多种。但是本文将介绍一种全新的实现方式&#xff0c;使用SVG来实现倒计时功能。本文主要用到了SVG的stroke-dasharray和stroke-dashoffset特性。下图是倒计时运行效果&#xff1a;SVG倒计时案例下面说说相关的实现代码。cs…

初学大数据之Python中5个最佳的数据科学库的学习

在下载了pycharm软件以及通过前两篇文章&#xff0c;配置了相应的模块包之后&#xff0c;那就开始对常用的模块的学习&#xff0c;以便后期利用这些模块对数据做模型化处理。 如果你已经决定把Python作为你的编程语言&#xff0c;那么&#xff0c;你脑海中的下一个问题会是&…

模拟银行自动提款系统python

列出对象及属性名称行为...py 人 类名&#xff1a;Person 属性&#xff1a;姓名 身份证号 电话 卡 行为&#xff1a;卡 类名&#xff1a;Card 属性&#xff1a;卡号 密码 余额 行为&#xff1a;银行 类名&#xff1a;Bank 属性&#xff1a;用户列表 提款机提款机 类名&#xf…

sklearn中常用的数据预处理方法

常见的数据预处理方法&#xff0c;以下通过sklearn的preprocessing模块来介绍; 1. 标准化&#xff08;Standardization or Mean Removal and Variance Scaling) 变换后各维特征有0均值&#xff0c;单位方差。也叫z-score规范化&#xff08;零均值规范化&#xff09;。计算方式是…