前言:
本文基于jdk1.8,如有写的不对的地方,欢迎指出。
这篇文章主要讲List接口的三个实现类,贴图。
在了解List之前最好了解一下数据结构的基础,推荐一个公众号Java3y,里面有很多关于java的基础知识,Java实现单向链表,栈和队列就是这么简单,二叉树就这么简单。
开始正题。
一:ArrayList
如图所示为ArrayList的结构。
如果想了解ArrayList的父类及实现接口的话可以自行百度,这里就不深入讲了,接下来看看ArrayList的源码。
1:属性
2:构造器
3:add(E e)方法
在增加元素时会先将数组实际长度+1。
如果当前数组为DEFAULTCAPACITY_EMPTY_ELEMENTDATA(空数组),则取默认扩容大小跟实际长度+1的最大值,得到最大的容量,不浪费系统资源,如果扩容后数组的长度大于原数组的长度,则调用扩容方法grow()
oldCapacity为原数组长度,newCapacity为原数组扩容后的长度如果扩容后的长度无法满足需要扩容的长度的话,就取需要扩容的长度,所以网上说的扩容1.5倍其实是不准确的。该扩容方法重点讲三个点:移位运算符、最大扩容长度及copyof方法。
(1):
java中有三种移位运算符
<< : 左移运算符,num << 1,相当于num乘以2
>> : 右移运算符,num >> 1,相当于num除以2
>>> : 无符号右移,忽略符号位,空位都以0补齐
具体运算规则是转化为二进制数进行移位操作,相对于 oldCapacity + (oldCapacity/2)性能会好点,具体可以参考这篇文章java中的移位运算符。
(2):最大扩容长度为Integer.MAX_VALUE。
(3):Arrays.copyOf()方法是java.util包下面的一个方法,具体作用是创建一个新数组,把数据依次插入到新数组。(由于arraycopy是java本地方法,是由c++写的,所以这里就不扩展了,有兴趣的朋友可以自行百度)
另外提两点:1:add方法是不是原子性的操作,所以是线程不安全的,集合工具包有提供创建线程安全的集合的方法List list = Collections.synchronizedList(new ArrayLIst()),具体可自行了解。2:删除元素时不会减少容量,若希望减少容量则调用trimToSize()
ArrayList就讲到这里,类里面的其他方法都比较简单,大家可以阅读源码自行了解。
二:Vector
Vector跟ArrayList的最大区别就是Vector是线程安全的,看源码,方法都是synchronized修饰的,所以牺牲了很大一部分性能,另外一点就是ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。
三:LinkedList
如图所示为LinkedList的结构,LinkedList实现了Deque接口,所以我们可以像操作栈喝队列一样操作LinkedList。
1:属性
LinkedList就三个属性,实际容量,头节点跟尾节点
2:构造方法
3:add方法
就是往链表尾节点添加元素的操作。
LinkedList的方法太多了,这里就不一一讲解了,都比较简单。
补充一点:
ArrayList增删慢不是绝对的(在数量大的情况下):
如果一直使用add方法增加元素(增加到末尾)的话,那是ArrayList要快,一直删除末尾的元素或者删除中间位置的元素也是ArrayList要快(不涉及移位操作)。
但一般来说:增删多还是用LinkedList,因为上面的情况是不常见。