ArrayList简述
ArrayList
的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。该篇文章 我们只简单分析add get方法
ArrayList 使用
ArrayList<Object> objects1 = new ArrayList<>(10);
objects1.add(2,new boolean[]);
objects1.get(3);
objects1.remove(2);
objects1.remove(new boolean[])
从remove方法就可以看出 里面保存的是对象
1、new ArrayList<>(10)源码分析
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//这个就能看出底层是数组 初始化数组长度为10 因为我们是Object 数组的默认值是null
//数组默认值参考 https://blog.csdn.net/duyiwuerluozhixiang/article/details/85797745
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果初始化化传值是0 那么 初始化的数组长度为0
//Object[] EMPTY_ELEMENTDATA = {}
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
2、add方法源码分析 该方法是android.jar提供的
public void add(int index, E element) {
//size指的是我们添加的数据的长度 不包含数组默认值数量 比如 {2,3,5,0,0} 如果这个0不是用户传入的 那么size是3
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//判断是否要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//System.arraycopy和Arrays.copyOf()的区别 可参考 https://www.jianshu.com/p/840976f14950
//主要是为了插入 选择插入的位置 通过移动的方式 将index后面的数据依次往后移动一个
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//插入数据
elementData[index] = element;
size++;
}
--------------------------------------------
//ensureCapacityInternal 方法
//此刻minCapacity 是 size+1
private void ensureCapacityInternal(int minCapacity) {
//如果构造函数initialCapacity 传入的是0 那么elementData是空数组 如果不是0 那就走后面
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//DEFAULT_CAPACITY默认值是10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//elementData不是空数组
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//如果真实的数组数据长度大于之前设置数组的数据长度 那么就扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
--------------------------------------
//grow 扩容方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//通过位运算 使其新数组长度是之前的1.5倍
//负数在二进制的表示 https://www.jianshu.com/p/6c518e7b4690
//位运算的左移右移 https://blog.51cto.com/u_13536788/3231257
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果扩容后的数组长度 还是小于真实长度 那么这个地方索性就直接使用真实长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//这个地方是直接复制一个新数组 长度为newCapacity 并将之前数据的数据copy到新数组来
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3、get方法
objects1.get(3);
public E get(int index) {
//index >= size 虽然数组默认长度可能比较大 如{1,3,4,0,0} 因为这个0 可能是初始默认值
//size呢 是我们真实通过add添加进去的 所以比较的是index >= size 而不是index >= elementData.length
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return (E) elementData[index];
}
注意
1、使用默认构造器实例化的ArrayList,在第一次添加元素和第11次添加元素时才会触发扩容。也就是第一次时,和超过数组容量时添加才触发扩容。
2、ArrayList 和
LinkedList` 都是不同步的,也就是不保证线程安全;因为没有用到锁的机制
总结
我们日常使用的都是add get方法 ,该文章也只是针对这个方法的分析。如果想更多的了解ArrayList原理以及它的优缺点。可参考以下文章