ArrayList
和Vector不同,ArrayList中的操作是线程不安全的。所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。
实现了Cloneable接口,即覆盖了函数clone( ),能被克隆。
实现java.io.Serializable接口,意味着ArrayList支持序列化,能通过序列化去传输。
直接用transient修饰数组。
1 | //类的版本控制的序列号 |
1 | transient Object[] elementData; |
add()
1 | public void add(int index, E element) { |
foreach
编译器会把它转换成类似代码
1 | Iterator |
jdk 1.7中实现 Iterable 接口,接口中要求实现Iterator方法。
1.8中,定义了一个抽象方法。
1 | public abstract Iterator |
1 | //迭代器允许调用者使用良好的语义在迭代期间从基础集合中删除元素。代替了枚举接口Enumeration |
其中Itr是一个成员内部类,实现了Iterator接口。
1 | private class Itr implements Iterator<E> { |
LinkedList
modCount++同样也是为了记录修改次数,便于检测中间的结构性变化。
添加方法
1 | void linkLast(E e) { |
获取元素方法
1 | Node |
若索引部分在前半部分,则从头结点开始查找,否则从尾结点开始查找。
1 | public int indexOf(Object o) { |
插入新元素
1 | void linkBefore(E e, Node |
步骤:
新建一个节点,先获得待插入节点的前驱。
1
newNode = new Node<>(pred, e, succ);
后继的前驱指向新节点
1
succ.prev = newNode;
前驱的后继指向新节点
1
prev.next=newNode;
删除元素
1 | E unlink(Node |
删除 x 节点,则让 x 的前驱和后继节点直接连接起来,
ArrayDeque
基于数组实现的双端队列,相当于实现了一个循环数组。
1 | private static int calculateSize(int numElements) { |
最关键的地方是其中的位或运算.首先,那一大串的位或运算的目的是为了得到传入的numElements的下一个2的次方数。比如传入的10,则得到16;传入16,得到32。那么经过五次的位或运算和右移运算就能够得到2^k-1的数。最后,得到的数加1即可。
示意图如下:
1 | 0 0 0 0 1 ^ ^ ^ ^ ^ |