集合--ArrayList、Vector、LinkedList
3.4 ArrayList底层结构和源码分析
ArrayList 注意事项:
- permits all elements ,including null,ArrayList可以存放 null ,并且多个
- ArrayList 是由数组来实现数据存储
- ArrayList 基本等同于 Vector ,除了ArrayList是线程不安全(执行效率高),看源码,多线程情况下不建议使用 ArrayList
ArrayList的扩容机制
- ArrayList中维护了一个Object类型的数组 elementData
-
transient Object[] elementData;
//transient 表示瞬间、短暂的,表示该属性不会被序列化
- 当创建对象时,如果使用的是无参构造器 (ArrayList()) ,则初始 elementData 容量为0 。
第1次添加,则扩容 elementData 为10;如果需要再次扩容的话,则扩容 elementData 为1.5倍
- 如果使用的是指定大小的构造器 (ArrayList( int )) ,则初始 elementData 容量为指定大小。如果需要扩容,则直接扩容 elementData 为1.5倍。
ArrayList的底层源码分析
注意:Idea 默认情况下, Debug 显示的数据是简化后的,如果希望看到完整的数据,需要进行设置
1.使用无参构造
//使用无参构造器创建ArrayList对象
ArrayList list = new ArrayList();
//使用for循环给list集合添加 1-10 数据
for(int i = 1; i<= 10; i++){
list.add(i);
}
//使用for循环给list集合添加 11-15 数据
for(int i = 11; i<= 15; i++){
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);




然后一层层往上返回到 add ,再往下返回到 grow()
如果 ensureExplicitCapacity(int minCapacity) 中,if语句不满足,则直接返回
2.使用有参构造
//使用有参构造器创建ArrayList对象
ArrayList list = new ArrayList(8);
//使用for循环给list集合添加 1-10 数据
for(int i = 1; i<= 10; i++){
list.add(i);
}
//使用for循环给list集合添加 11-15 数据
for(int i = 11; i<= 15; i++){
list.add(i);
}
list.add(100);
list.add(200);
list.add(null);

后续和无参构造的流程相同,只是扩容机制开始就按1.5倍
3.5 Vector底层结构和源码分析
Vector 基本介绍:
-
Vector类的定义说明
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable -
Vector底层也是一个对象数组,protected Object[] elementData;
-
Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
public synchronized E get(int index) { if (index >= elementCount) throw new ArraylndexOutOfBoundsException(index); return elementData(index); } -
在开发中,需要线程同步安全时,考虑使用Vector
Vector 和 ArrayList 的比较:
| 底层结构 | 版本 | 线程安全(同步)效率 | 扩容倍数 | |
|---|---|---|---|---|
| ArrayList | 可变数组 | jdk1.2 | 不安全,效率高 | 如果有参构造:1.5倍;如果是无参:第一次10,第二次开始1.5倍 |
| Vector | 可变数组Object[] | jdk1.0 | 安全,效率不高 | 如果是无参,默认10,满后按2倍扩容;如果指定大小,则每次直接2倍扩 |
Vector源码
//无参构造器
Vector vector = new Vector;
for(int i = 1; i<= 10; i++){
vector.add(i);
}
vector.add(100);
/*
1.new Vector() 底层
public Vector(){
this(10);
}
2.vector.add(i)
2.1 //下面这个方法就是添加数据到 Vector 集合
public synchronized boolean add(E e){
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
2.2 //确定是否需要扩容 条件: minCapacity - elementData.length>0
private void ensureCapacityHelper(int minCapacity){
//overflow-conscious code
if(minCapacity - elementData.length>0){
grow(minCapacity);
}
}
2.3 //如果需要的数组大小不够用,就扩容,扩容的算法
//newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
//就是扩容两倍
private void grow(int minCapacity){
//overflow-conscious code
int oLdCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
if(newCapacity - minCapacity<0)
newCapacity = minCapacity;
if(newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
*/
3.6 LinkedList底层结构和源码分析
LinkedList 全面说明:
- LinkedList底层实现了双向链表和双端队列特点
- 可以添加任何元素(元素可以重复),包括null;
- 线程不安全,没有实现同步
LinkedList 底层操作机制:
-
LinkedList底层维护了一个双向链表.
-
LinkedList中维护了两个属性first和last,分别指向首节点和尾节点
-
每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过 prev 指向前一个,通过 next 指向后一个节点。最终实现双向链表。
-
所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
-
模拟一个简单的双向链表
public class LinkedList{ public static void main(String[] args){ //模拟一个简单的双向链表 Node jack = new Node("jack"); Node tom = new Node("tom"); Node hsp = new Node("hsp"); //连接三个结点,形成双向链表 //jack -> tom -> hsp jack.next = tom; tom.next = hsp; //hsp -> tom -> jack hsp.pre = tom; tom.pre = jack; Node first = jack;//让first引用指向jack,就是双向链表的头结点 Node last = hsp;//让last引用指向hsp,就是双向链表的尾结点 //演示,从头到尾进行遍历 while(true){ if(first == null){ break; } //输出 first 信息 System.out.println(first); first = first.next; } //演示,从尾到头进行遍历 while(true){ if(last == null){ break; } //输出 last 信息 System.out.println(last); last = last.pre; } //演示链表的添加对象/数据,是多么方便 //要求,在 tom 和 hsp 之间添加,插入一个对象 smith //1.先创建一个 Node 结点, name就是 smith Node smith = new Node("smith"); //下面就把 smith 加入到双向链表 smith.next = hsp; smith.pre = tom; hsp.pre = smith; tom.next = smith; } } //定义一个 Node 类,Node 对象表示一个双向链表的一个结点 class Node{ public Object item; //真正存放数据 public Node next;//指向后一个结点 public Node pre;//指向前一个结点 public Node(Object name){ this.item = name; } public String toString(){ return "Node name=" + item; } }
LinkedList 增删改查案例:
LinkedList linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
/* 添加:
1. LinkedList linkedList = new LinkedList();
public LinkedList() {}
2.这时 LinkeList 的属性 first = null last = null
3.执行 添加
pubLic boolean add(E e){
linkLast(e);
return true;
}
4.将新的结点,加入到双向链表的最后
void linkLast(E e){
final Node<E> l= last;
final Node<E> nerode = new Node<>(l, e, null);
last = newNode;
if (l == nuLL)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
*/
//演示一个删除节点
linkedList.remove();//这里默认删除的是第一个结点
/* 删除:linkedList.remove();//这里默认删除的是第一个结点
1. 执行 removeFirst
public E remove(){
return removeFirst();
}
2.执行
public E removeFirst(){
final Node<E> f = first;
if (f == nuLL)
throw new NoSuchELementException();
return unlinkFirst(f);
}
3.执行 unlinkFirst ,将 f 指向的双向链表的第一个结点拿掉
private E unlinkFirst(Node<E> f){
//assert f == first && f != null;
final E element= f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == nuLl)
last= null;
else
next.prev = null;
size--;
modCount++;
return element;
}
*/
//修改某个结点对象
LinkedList.set(1, 999);
System.out.printLn("linkedList=" + linkedList);
//得到某个结点对象
//get(1)是得到双向链表的第二个对象
Object o = linkedList.get(1);
System.out.println(o);//999
//因为LinkedList是 实现了List接口,遍历方式
Iterator iterator= linkedList.iterator();
while(iterator.hasNext()){
Object next = iterator.next();
}
//LinkedList的增强for
for(Object o1: linkedList){
System.out.println(o1);
}
//传统for循环也可以
ArrayList 和 LinkedList 的比较:
| 底层结构 | 增删的效率 | 改查的效率 | |
|---|---|---|---|
| ArrayList | 可变数组 | 较低,数组扩容 | 较高 |
| LinkedList | 双向链表 | 较高,链表扩容 | 较低 |
如何选择ArrayList和LinkedList
- 如果我们改查的操作多,选择ArrayList
- 如果我们增删的操作多,选择LinkedList
- 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择 ArrayList
- 一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另-个模块是LinkedList.

浙公网安备 33010602011771号