ArrayList、LinkedList原理
List
ArrayList
ArrayList的底层是基于动态数组实现
transient Object[] elementData; private int size;
常用的方法
ArrayList<String> arrayList = new ArrayList<>(); //或者ArrayList<String> arrayList = new ArrayList<>(4);arrayList.add("a"); //添加元素,在数组“尾部”添加 速度快arrayList.add(0,"c"); //添加元素,在数组“中间”添加 速度慢System.out.println(arrayList.get(0)); //获取指定下标的元素arrayList.remove("a"); //删除指定元素,通过遍历arrayList.remove(0); //删除指定下标的元素arrayList.set(0,"b"); //修改
深入原理
初始化
ArrayList<String> arrayList = new ArrayList<>();
当调用ArrayList的无参构造器时,数组容量为0的Object数组;
当调用add()方法添加第一个数据时,才会分配容量,默认容量为10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
ArrayList<String> arrayList = new ArrayList<>(10);
当调用ArrayList的有参构造器时,会创建一个指定大小的Object数组;
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}
add方法、扩容
public boolean add(E e) {// 检查当前容量是否还可以容纳一个元素,不够则扩容ensureCapacityInternal(size + 1); // Increments modCount!!// 添加到数组末尾// 这个语句可以分解为// elementData[size] = e;// size += 1;elementData[size++] = e;return true;}
在使用无参构造器初始化ArrayList时,便会创建一个空的数组;
当调用add()方法添加第一个数据时,便会对数组进行扩容(调用Arrays.copyOf方法),默认容量为10;
若添加数据后的容量 超出 当前数组长度,则进行扩容,扩容之后的容量为之前容量的1.5倍;
https://blog.csdn.net/zhouhengzhe/article/details/108319369
把原数组的数据,原封不动的复制到新数组中,然后把ArrauList的地址指向新数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEgSRtqY-1621011446037)(https://note.youdao.com/yws/res/85142/74452E4097A64D99AAF89E5C4DF3DD38)]
1.7的时候是初始化就创建一个容量为10的数组,1.8后是初始化先创建一个空数组,第一次add时才扩容为10;
LinkedList
LinkedList是通过双向链表实现的
transient int size = 0;transient Node<E> first;transient Node<E> last;
常用方法
LinkedList基本使用与ArrayList相同;
LinkedList<String> linkedList = new LinkedList<>(); //注意,LinkedList没有有参构造器linkedList.add("a");linkedList.set(0,"b"); //效果等同linkedList.add(0,"c");linkedList.remove(0);linkedList.remove("c");System.out.println(linkedList.get(0));
remove
remove操作分2种,一种是根据下标删除,一种是根据元素内容删除;
根据元素内容删除时,需要遍历全部元素;
根据下标删除remove(int index)
若index < size/2,则从头遍历,否则从尾部遍历;
get(int ndex)
若index < size/2,则从头遍历,否则从尾部遍历;
ArrayList与LinkedList对比
ArrayList在使用无参构造器时,默认初始化一个容量为10的数组,当添加元素后 元素个数 大于 现有容量,则按1.5倍容量扩容,扩容 消耗性能,所以初始化时最后指定容量;
LinkedList是双向链表,当指定下标 添加、删除元素时,若index < size/2则从头节点遍历,否则从尾节点开始遍历;
当指定下标添加(不是修改指定下标元素)或者删除元素时,只需修改指针即可
ArrayList
- 指定下标删除元素慢 list.remove(int index)
- 指定下标添加元素慢 list.add(int index,E e)
- 指定下标查询快 list.get(int index)
LinkedList
- 指定下标删除元素快 list.remove(int index)
- 指定下标添加元素快 list.add(int index,E e)
- 指定下标查询慢 list.get(int index)
需要先定位到元素所在
List与线程安全
Collections.synchronizedList()
ArrayList 与 LinkendList都不是线程安全的,但可以通过 java.util.Collections.synchronizedList(List list) 方法,获取一个线程安全的 List 实例对象;
Collections.synchronizedList(List list) 方法源码public static <T> List<T> synchronizedList(List<T> list) {return (list instanceof RandomAccess ?new SynchronizedRandomAccessList<>(list) :new SynchronizedList<>(list));
}
当传入的 list 是 ArrayList 时,返回 SynchronizedRandomAccessList 对象;传入 LinkedList 时,返回 SynchronizedList 对象。
get、set、add 等操作都添加了synchronized锁;
public E get(int index) {synchronized (mutex) {return list.get(index);}}public E set(int index, E element) {synchronized (mutex) {return list.set(index, element);}}public void add(int index, E element) {synchronized (mutex) {list.add(index, element);}}public E remove(int index) {synchronized (mutex) {return list.remove(index);}}
CopyOnWriteArrayList
坑点
迭代器
增强for循环 的 原理就是 迭代器,这点与普通的for循环有着本质的区别;
https://juejin.cn/post/6844903569095671816
在迭代器中,不能对list进行增删操作,只能查询;
即list的add、remove会报ConcurrentModificationException异常
public static void main(String[] args) {ArrayList<String> strings = new ArrayList<String>();strings.add("a");strings.add("b");for (String string : strings) {if ("e".equals(string)) {strings.remove(string);}}}Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)at java.util.ArrayList$Itr.next(ArrayList.java:831)at main.java.mo.basic.ConcurrentModificationExceptionTest.main(ConcurrentModificationExceptionTest.java:17)
Iterator实现类有2个重要的方法hasNext()和next()Iterator中有一个expectedModCount属性与list的modCount属性同步,当list执行remove时会modCount++,而Iterator中有expectedModCount却不会变化;当 Iterator调用next()方法,会使用checkForComodification做校验,modCount与 expectedModCount不同就会报错;
解决方法,使用普通的for循环,不要使用迭代器;
ArrayList、LinkedList原理相关推荐
- List 系列 ArrayList LinkedList CopyOnWriteArrayList Queue系列 ArrayDeque ConcurrentLinkedDeque LinkedBlo
LinkedBlockingDeque作为一种阻塞双端队列,提供了队尾删除元素和队首插入元素的阻塞方法.该类在构造时一般需要指定容量,如果不指定,则最大容量为Integer.MAX_VALUE.另外, ...
- Vector ArrayList Hashtable HashMap ArrayList LinkedList
1. Vector & ArrayList 1) Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的 ...
- java vector arraylist linkedlist用法与区别
首先,它们是list的实现类,大致说一下vector arraylist linkedlist的区别. 1.线程安全来讲, vector是线程安全,arraylist linkedlist线程不安全. ...
- ArrayList,LinkedList,Vector的异同点
先总结下ArrayList和LinkedList的区别: 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayLi ...
- java linkedlist实例_Java Linkedlist原理及实例详解
这篇文章主要介绍了Java Linkedlist原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定义:linkedlist属于链表结构 ...
- ArrayList, LinkedList, Vector - dudu:史上最详解
ArrayList, LinkedList, Vector - dudu:史上最详解 我们来比较一下ArrayList, LinkedLIst和Vector它们之间的区别.BZ的JDK版本是1.7.0 ...
- ArrayList底层原理
ArrayList底层原理 ArrayList在工作中经常用到,今天来看一下ArrayList的底层是如何实现的?在这之前,先抛出几个问题. 1.ArrayList底层实现的数据结构是什么? 2.Ar ...
- Collection,List,ArrayList,LinkedList集合
Collection集合 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素 lJDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现 Coll ...
- ArrayList ,LinkedList,Vector,StringBuilder,StringBuffer ,String,HashMap,LinkedHashMap,TreeMap
ArrayList ,LinkedList,Vector 区别和联系 从上面的类层次结构图中,我们可以发现他们都实现了List接口,它们使用起来非常相似.区别主要在于它们各自的实现,不同的实现导致了不 ...
- ArrayList LinkedList与HashMap 实现原理
ArrayList 定义 快速了解ArrayList究竟是什么的一个好方法就是看JDK源码中对ArrayList类的注释,大致翻译如下: /** * 实现了List的接口的可调整大小的数组.实现了所有 ...
最新文章
- 矩阵转置 java_Java 创建矩阵并转置矩阵
- Android - N级树形结构实现
- 阿里百万级规模开源容器 PouchContainer GA 版本发布,邀您参与上海 Meetup 共话容器未来
- 天天象棋 残局闯关 第18关
- boost::spirit模块使用 phoenix 进行实际表达式评估的语法和语义操作的测试程序
- noip2008普及组4题题解-rLq
- C# 开发圆角控件的具体实现
- uva 11383(二分图最大权匹配)
- 虚拟局域网软件开源_ZeroTier虚拟局域网免费远程桌面体验--替代TeamViewer
- 网络监控系统安装的4种方式,安防必备
- Spring Boot2 整合 MyBatis 多数据源
- vue Cli 环境删除与重装 - 版本文档
- RabbitMq学习笔记002---RabbitMq在SpringBoot中的应用_配置_使用_并且设置优先级
- 4、Spring配置中的classpath:与classpath*:的区别
- android 中如何监听耳机键消息
- 关于利用 achartengine 画 股票 分时线
- matlab解决线性规划问题
- 项目工作说明书(SOW)
- 双重差分模型能做固定效应吗_双重差分法的平行趋势假定
- solr6.3与MySQL结合使用
热门文章
- 房子买贵了?房价收入比(house-price‑to‑income ratios)指标揭秘真相
- php合成图片系统,php图片合成
- win7 时间服务器地址修改,win7 时间服务器地址修改
- TensorFlow基础:Session(会话)
- swift5 修改Accessibility order读取的顺序
- 翻译:swift 5初始化 被忽略的Convenience便捷初始化、Required和继承
- 翻译:响应式编程或反应式编程 RxSwift和RxCocoa 从入门到精通 Reactive programming
- 对比两个文件内容差异VS Visual Studio Code
- mysql和oracle的时间字段区别_Oracle数据库中关于日期和时间字段类型
- 发布传参_Taro 1.2.9 发布,BAT 小程序、H5 与 RN 端统一框架