java list 博客园_Java基础知识_List集合

一、ArrayList解析

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

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

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

b3f4441acf3e545fd248ff4ec488cc90.png

DEFAULT_CAPACITY是初始化容量

EMPTY_ELEMENTDATA是指定该ArrayList的容量为0时,返回空数组

DEFAULTCAPACITY_EMPTY_ELEMENTDATA它与上面的区别是,该数组是默认返回的,而后者是在用户指定的容量为0时返回。

elementData保存添加ArrayList的元素

size是ArrayList的实际大小

根据上面我们可以发现,Array List底层其实就是一个数组,ArrayList有扩容这个概念,正因为它扩容,所以可以实现动态增长。

1.2 构造方法

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

f5e0cfa9e2740e47aed0dee94daf0b0b.png

如果指定了容量,那么数组就初始化成对应的容量,否则返回的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA

1.3 Add方法

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

d014eb7c0c54361d09231ff7758c6f69.png

1.3.1 add(E e)

步骤:

检查是否需要扩容

插入元素

首先,我们来看这个方法

1 public booleanadd(E e) {2 ensureCapacityInternal(size + 1); //Increments modCount!!

3 elementData[size++] =e;4 return true;5 }

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

确认list容量,尝试容量加1,看看有无必要

添加元素

接下来我们来看看这个容量即1是否满足我们的需求

56855bf1b8321e5e179141cf84256af9.png

我们看ensureExplicitCapacity,如果要的最小容量比数组长度要大,就调用grow来扩容

接下来我们来看看grow是怎么实现的

60153bb3609b0d09da3c97ca8e2d96bf.png

相当于扩容1.5倍

进去看copyOf方法

13aeedb2f3b93f4098abbdca57a6f996.png

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

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

扩容到原来的1.5倍

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

足够:直接添加

不足够:扩容

1.3.2 add(int index,E element)

步骤

检查角标

空间检查,如果有需要进行扩容

插入元素

我们来看看插入的实现

eea7e538d2dde865561a88112bb69b47.png

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

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

1.4 get方法

检查角标

返回元素

61a091ffd1d0f0bfbb4f82693b9a0c56.png

1 //检查角标

2 private void rangeCheck(intindex) {3 if (index >=size)4 throw newIndexOutOfBoundsException(outOfBoundsMsg(index));5 }6

7 //返回元素

8 E elementData(intindex) {9 return(E) elementData[index];10 }

1.5 set方法

步骤

检查角标

替代元素

返回旧值

da4b11f10417debe5d3af22a18a53dbd.png

1.6 remove方法

步骤

检查角标

删除元素

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

设置为null,让gc回收

35e9ae86b47cfd6bc1bac90b9e0e0567.png

numMoved是指需要向左移动的个数

1.7细节再说明

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

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

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

它不是线程安全的,可以存放null值

二、Vector与ArrayList的区别

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

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

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

有synchronized关键字

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

如果想要ArrayList实现同步,则可以使用Collections工具类的方法

1 List list = Collections.synchronizedList(new ArrayList(...));

就可以实现同步了。

还有另一个区别

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

三、LinkedList解析

LinkedList底层是双向链表,从结构上看到了LinkedList实现了Deque接口,所以我们可以操作LinkedList像操作队列和栈一样

befc4887e9009373ea559d8e072bd083.png

ListedList变量就这几个

932c042e815162f56b0f68ad1c615b2e.png

3.1  构造方法

LinkedList构造方法有两个

650ece909101b3a04e5e64457de717c3.png

3.2 add方法

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

1 public booleanadd(E e) {2 linkLast(e);3 return true;4 }5

6 voidlinkLast(E e) {7 final Node l =last;8 final Node newNode = new Node<>(l, e, null);9 last =newNode;10 if (l == null)11 first =newNode;12 else

13 l.next =newNode;14 size++;15 modCount++;16 }

3.3 remove方法

0b1342c8df0f4454bba74e686c7aa25f.png

8a35ee6fb75581083a9ed3eb0a10fb34.png

实际上就下面图的操作

ec96c5e4b6b448757bac7a3cef462221.png

3.4 get方法

可以看到get方法实现就两段代码

1 public E get(intindex) {2 checkElementIndex(index);3 returnnode(index).item;4 }

我们进去看一下具体怎么实现的

下标要是小于长度的一半就从头遍历,否则从未遍历

f83e6232482ce47f1b134fc1f6ca9863.png

3.5 set方法

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

1 public E set(intindex, E element) {2 checkElementIndex(index);3 Node x =node(index);4 E oldVal =x.item;5 x.item =element;6 returnoldVal;7 }

四、总结

ArrayList

底层是数组实现,默认容量是10,每次扩容增加原先容量的一半,增删的时候,需要数组拷贝复制,native方法由c/c++实现

LinkedList

底层是双向链表(双向链表方便往前遍历)

Vector:底层是数组,现在很少用基本上被ArrayList替代,原因有两个

Vector所有方法都是同步的,有性能损失

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

总的来说,增删多用linkedlist,查找多用ArrayList

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值