image-20200716114132581
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
特点:
优点:
缺点:
链表通过指针将一组零散的内存块串联在一起的线性数据结构,把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址,记录下个结点地址的指针叫作后继指针 next。
如下图所示:
image-20200716143134994
特点:
优点:
缺点:
其他链表:
image-20200716173146870
image-20200716173502165
数据结构实现
访问效率
增加和删除效率
综合来说,在需要频繁读取集合中的元素时,更推荐使用ArrayList,而在插入和删除操作较多时,更推荐使用LinkedList。
ArrayList 底层是数组,ArrayList 初始长度为 10
image-20200717170610239
按照下标添加,每次添加都会判断集合的容量
什么时候发生扩容:
image-20200717171043520
扩容流程:
判断数组长度够不够添加新元素
image-20200717171743560
不够就触发扩容 grow方法
//真正的扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新的容量是在原有的容量基础上+50% 右移一位就是二分之一
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量小于最小容量,按照最小容量进行扩容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//这里是重点 调用工具类Arrays的copyOf扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
创建集合的时候如果能够预估长度,最好指定集合大小
image-20200717155506620
ArrayList 线程不安全
Vector 线程安全 Vector几乎所有的方法都加了锁
1598926062661
CopyOnWriteArrayList 读不加锁写加锁
复制写:复制一个新数组 将元素添加新数组中
public boolean add(E e) {
创建锁对象
final ReentrantLock lock = this.lock;
加锁
lock.lock();
try {
获取现有数组
Object[] elements = getArray();
获取现有数组长度
int len = elements.length;
根据现有数组得到一个长度+1的新数组 【复制】
Object[] newElements = Arrays.copyOf(elements, len + 1);
将要添加的元素 写入新数组中
newElements[len] = e;
用新数组替换老数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
1.7 数组+链表
1598943151710
1.8 数组+链表+红黑树
如果链表的长度大于8 链表就会处理为树结构
1598943495683
默认初始值 16
1598943720885
默认初始值(数组的长度):16
1598943739052
负载因子:0.75
1598943762994
扩容的条件:当底层数组 四分之三 的位置有了元素 就扩容
hash碰撞,两个key计算的结果都是同一个下标
Entry
1598944106163
不是
Hashtable
1598944691036
ConcurrentHashMap
1.7 分段锁
1598945352890
1.8 CAS 无锁算法(乐观锁)
加不加锁为条件进行分类
HashSet 底层是HashMap 只使用HashMap的key 不使用value
Queue ---》线程池