数据结构中的数组
从数据结构分类上数组是是一种物理的数据结构,常见的物理结构还是链表。数组的定义就是:有限个相同类型的元素的有序集合,其特点是内存一般空间顺序存储,随机访问效率高(根据索引获取元素),时间复杂度为O(1)。下面从时间复杂度上看数组中的增、删、查这个操作的时间复杂度;
- 添加操作:O(n),这里O(n)是消耗在数组扩容上;
- 删除操作:O(n),删除操作后需要挪动元素。
- 读取操作:O(1),根据索引查询元素;
- 更新操作:O(1),这里的更新是指更具指定索引进行更新。
Java中的数组
数组的基本用法
回到正题,笔者最近在看JDK1.8的源码,发下数组在底层有广泛的应用,因此用这篇文章记录数组的JDK源码进行了使用。因为数组的在定义时候就需要确定长度,那么数组往往伴随着个扩容的问题。本文也会对数组在不同类中的初始容量,扩容的时机(什么时候 出发扩容),扩容的机制(扩容后的容量为原来的多少倍)进行简单的记录,但是详细的扩容细节就不过多分析。
1.java.lang包
String
private final char value[]; //底层是用字符数组存放数据,而且用final修饰
AbstractStringBuilder
该类其实就是StringBuilder和StringBuffer的父类
char[] value; //底层也是用字符数组存储数组,但是这里不是用final修饰的
ThreadLocal.ThreadLocalMap
private Entry[] table; //数组存储不同的ThreadLocal的信息,Entry为key-value形式的哈希表
- 默认容量:16;
- 扩容时机:数组元素超过数组当前容量的三分之二;
- 扩容机制:扩容后的容量是原来容量的 2 倍;
2.java.util包
ArrayList
transient Object[] elementData; //存放list元素的数组(transient不参与序列化的过程)
- 默认容量:10;
- 扩容时机:数组满的时候;
- 扩容机制:扩容后的容量是原来容量的 1.5 倍;
HashMap
transient Node<K,V>[] table; //存放数据的数组
Node类型可能为链表中节点或者红黑树的节点
- 默认容量:16;
- 扩容时机:当前结合中元素大于(数组当前容量*负载因子),负载因子是0.75。
- 扩容机制:为原来容量的两倍;
Hashtable
private transient Entry<?,?>[] table;
Entry是链表节点类型
- 默认容量:11;
- 扩容时机:当前结合中元素大于(数组当前容量*负载因子),负载因子是0.75。
- 扩容机制:为原来容量的两倍再加1;(HashMap是原来的两倍)
Vector
protected Object[] elementData; //存储数据的元素
- 默认容量:10;
- 扩容时机:数组满的时候;
- 扩容机制:扩容后的容量是原来容量的 2 倍;(ArrayList是1.5倍数)
3.java.util.concurrent包
ArrayBlockingQueue
final Object[] items; //队列元素存放在该数组中,数组大小必须在初始化的时候赋值,没有默认值
- 默认容量:没有默认容量,容量大小需要在构造实例时参数;
- 扩容机制:该类是一个阻塞队列,不会有扩容的逻辑,当数组满的时候,就会阻塞添加操作或添加失败。
CopyOnWriteArrayList
private transient volatile Object[] array; //底层也是基于数组,volatile修饰保证可见性
- 默认容量:0
- 扩容机制:添加元素时通过拷贝数组进行扩容,扩容后容量为原来的容量加上添加的元素的个数。