ArrayList和LinkedList的区别、扩容机制以及底层的实现方式
作者:WINGZINGLIU 发布时间:2023-11-27 01:26:57
ArrayList和LinkedList区别、扩容机制及底层实现
ArrayList
ArrayList的底层实现为数组存储在内存中,线程不同步。可通过数组下标的形式进行查找,所以在查询方面的效率较为出色,常用在查询较多的情景下。
LinkedList
LinkedList的底层实现为链表形式,也为线程不同步。而链表的底层也决定了它在查询方面不如数组底层的ArrayList而在指定位置插入等修改操作下,性能优于ArrayList。
Vestor
另外还有Vestor,Vestor也是和ArrayList、LinkedList一样实现了java.util.List接口。最大的区别在于Vestor是线程同步的,所以在效率方面不如另外两者,适用于多线程项目中。
ArrayList的扩容机制
/**
* Constructs an empty list with the specified initial capacity.
*/
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
翻阅源码会发现ArrayList初始化如果不指定大小的时候 初始大小为10。
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
扩容的规则也在源码中有体现,扩容后的大小= 原始大小+原始大小/2 + 1。在进行插入等操作的时候,如果判断出大小不够,会依据此方法进行扩容。(以上是JDK1.6版本的源码,在JDK1.7中扩容规则进行了修改,改为了扩容后的大小= 原始大小+原始大小/2)
LinkedList的扩容机制
由于它的底层是用双向链表实现的,没有初始化大小,也没有扩容的机制。
ArrayList和LinkedList(常用方法、底层结构及扩容机制)
1.ArrayList解说
ArrayList初始长度为0(这里以jdk1.8为例),是一个Object类型的空数组,如下
当第一次调用add后,长度变为10
当数组首次扩容的10个空间用完需要扩容后,会第二次走grow方法来扩容(每次扩容为1.5倍)
总的来说:
ArrayList初始大小为10,每次1.5倍进行扩容;它的底层是用数组实现的,所以查询速度相对LinkedList要快。
2.LinkedList解说
(1)
* LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
* LinkedList 实现 List 接口,能对它进行队列操作。
* LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
* LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
* LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
* LinkedList 是非同步的。
由于它的底层是用双向链表实现的,所以它对元素的增加、删除效率要比ArrayList好;它是一个双向链表,没有初始化大小,也没有扩容的机制,就是一直在前面或者后面新增就好。
(2)LinkedList底层的数据结构是基于双向循环链表的,且头结点中不存放数据,如下:
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
header是双向链表的头节点,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该
节点所包含的值。size是双向链表中节点实例的个数。
总之,addBefore(E e,Entry<E> entry)实现在entry之前插入由e构造的新节点。而add(E e)实现在header节点之前插入由e构造的新节点。为了便于理解,下面给出插入节点的示意图。
来源:https://blog.csdn.net/WINGZINGLIU/article/details/83715578


猜你喜欢
- Java String类的concat方法在了解concat()之前,首先需要明确的是String的两点特殊性长度不可变值不可变这两点从源码
- 验证码功能在各大网站都能用到,下面小编通过实例代码给大家分享Android 获取随机验证码功能,具体代码如下所示: package cn.h
- spring的refresh方法前置知识方法入口// org.springframework.context.support.Abstrac
- 上次给一个网站写网站 前后端分离 最后跪在ajax跨域上面了 自己在网上找了个方法 亲试可用
- Java Resource路径首先一点很重要,Java中不存在标准的相对路径,各种相对路径取资源的方式都是基于某种规则转化为绝
- Sentinel流控模式Sentinel流量控制主要有以下几种模式:直接失败模式:在达到流量控制阈值后,直接拒绝请求,返回错误信息。关联模式
- 前言在unity的ugui中Text控件,有时我们会有各种各样的需求,比如类似html中css的text-overflow属性,希望一段文字
- 我就废话不多说了,大家还是直接看代码吧~private LineRenderer line;//画线line = this.gameObje
- C# Class写入Json/// <summary> /// 写入jso
- 本文实例为大家分享了java获取当前时间年月日的具体代码,供大家参考,具体内容如下import java.text.ParseExcepti
- 开发 Web 应用的思路实现一个简单的 JSP/Servlet。搭建创建 Web 应用工程的环境。创建 Web 应用工程。Web 应用工程的
- 在使用他人代码时,为不保留文件头部版权信息,需要一个个删掉,费时费力,写了个脚本,简单清除掉目录下所有的文件的头部版权信息。# -*- co
- 单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如
- 一、导航栏UINavigationBar1、导航栏的使用在iOS开发中,我们通常会使用导航控制器,导航控制器中封装了一个UINavigati
- 主要是这个方 * ist<string> GetAllFileNames(string path,string pattern=&
- public static void main(String[] args) { System.out
- 1.使用的注意事项本节给大家带来基础UI控件部分的最后一个控件:DrawerLayout,官方给我们提供的一个侧滑菜单控件,和上一节的Vie
- 什么是Junit5 ?先看来个公式:JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vin
- 序列化与反序列化Java对象是有生命周期的,当生命周期结束它就会被回收,但是可以通过将其转换为字节序列永久保存下来或者通过网络传输给另一方。
- 最近,项目上涉及到了图像压缩,发现原有的图像压缩功能,虽然保证了图像的大小300K以内,但是压缩后的图像看的不在清晰,并且,限定了图片的He