java list基础,Java基础一篇过(四)List这篇就够了

文章更新时间:2020/03/03

一、List介绍

list是Java的一个接口,继承了Collection,常用到的有3个子类实现:

ArrayList

底层数据结构是数组。线程不安全

LinkedList

底层数据结构是链表。线程不安全

Vector

底层数据结构是数组。线程安全

下面就这3个常用子类进行分析学习。

二、ArrayList

ArrayList位于java.util包下,由于英文水平有限,且注释又全是英文,我把里面的代码copy出来,并用自己的语言来整理并理解ArrayList

底层实现: 数组

特点:查询快,增删慢 (因为数组是有索引的,通过下标直接访问)

属性

ec1ad11b1a5b6ce86d30e90ae0cc60b2.png

构造方法

19d0e89a80f7134b2f3f6fa1f43b08d6.png

c16ff26dd0b71a80bdf8943084282173.png

9914bf1e4b7219bcaf1af9b277133955.png

add(E e)【在末尾添加元素】

f78cbd21669929db126479723ce519eb.png

8f96a97efa459d8bc80f92d3c85224bc.png

71bdb9dfa817e85134852f0f2a56db69.png

147d1cc8953c0112254ffc32a1cd3eb9.png

总结一下:首先去检查一下数组的容量是否足够

不足够:扩容

扩容到原来的1.5倍

第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity。

足够:直接添加

add(int index, E element)【在指定位置添加元素】

6e2b295d0b4f293c5b3b707f006c9450.png

PS:与扩容相关ArrayList的add方法底层其实都是arraycopy()来实现的看到arraycopy(),我们可以发现:该方法是由C/C++来编写的,并不是由Java实现

get(int index)【获取指定位置的元素】

2e6ce91ffc567f0c5d138363d51a5057.png

set(int index, E element)【在指定位置设置元素】

a10fb2661ad2620c31677d3c976f3785.png

341be933bfb8a7cb7f714868b10aa895.png

总结一下:

检查角标

删除元素

计算出需要移动的个数,并移动

设置为null,让Gc回收原来的对象

PS:删除元素时不会减少容量,若希望减少容量则调用trimToSize()

小结

ArrayList是基于动态数组实现的,在增删时候,需要数组的拷贝复制

ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍

删除元素时不会减少容量,若希望减少容量则调用trimToSize()

它不是线程安全的

它能存放null值

indexOf和lastIndexOf方法查找元素,若元素不存在,则返回-1!

三、LinkedList

简介

LinkedList也位于java.util包下,底层实现为链表。

底层实现: 线性链表

特点:增删快,查询慢(因为是链表结构,没有初始化大小,也没有扩容的机制,只用考虑在前面还是后面进行操作。)

PS:JDK1.5之前采用单向链表, JDK1.5之后采用双向链表

简单认识一下链表:

d5d45b6ebc71101e895a7a0d6ffd5707.png

链表结构中的每一个元素为Node对象,添加元素的时候实际上是对Node的操作:

45fb61c9884adabd0b85f6ea71ef4112.png

属性

84d313383808a5e3ba4abd5ccb4768ef.png

构造方法

构造方法主要都是根据入参来循环设置每一个Node对象的prev(前一个对象)和next(后一个对象),感兴趣的话可以看下底层的代码实现,这里就不详细写了

add【添加节点】

3cf89f7dee4b88e8464dbcd13ee34af6.png

933663088080660e0479d804a4a71790.png

图示:

b2b91c69093825af6310d87ddbe5032e.png

remove【删除节点】

a6071bfa65b9cb00c9ca57fb52f267f7.png

cbe41ea579971389e032a4e82404725d.png

unlink图示:

e76f8c0ed36eda95fa655b0570d97882.png

get【获取节点】set【设置节点】

原理都是查看角标是否大于长度的一半,若大于则从尾部遍历并操作元素,小于则从头部遍历并操作元素。(具体代码就不详细图解了)

小结

LinkedList的没有扩容方法,默认从尾部加入元素就是自动扩容

LinkedList是基于链表实现的,因此增删改效率高,查询效率低!

四、Vector

底层实现: 数组

特点:线程安全,但消耗内存,效率不高(因为方法都加了synchronized关键字。)

Vector与ArrayList异同:

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

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

ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。

大部分非多线程安全的场景下我们都使用ArrayList和LinkedList,现vector已基本废弃。

五、总结

ArrayList

底层实现是数组

ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍

在增删时候,需要数组的拷贝复制(navite 方法由C/C++实现)

LinkedList

底层实现是双向链表(1.5以后的版本,之前的是单向链表)

Vector

底层是数组,现在已较少使用

Vector所有方法都加了synchronized关键字实现同步,同步就意味着有性能损失。

Vector初始length是10,超过length时,以100%比率增长,相比于ArrayList消耗更多内存。

一句话小结:查询多用ArrayList,增删多用LinkedList,同步场景用Vector。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值