集合Collection
集合的长度是可变的,而数组的长度是不可变的,固定的 。
数组可以存储基本数据类型,也可以存储引用数据类型,而集合只可以存储引用数据类型
数组只能存放一种类型,而数组可以存放不同类型的,但是我们一般只存放一种类型 。
collection是集合的接口,它的子接口是list和set,他们都必须通过实现类来实现。
list接口的实现类主要又三种,ArrayList,LinkedList和Vector,而List下面的存储,可以存放可重复的元素,也是有序的,依次存储,Set下面的 则不可以。
collection:
接口的接口,对象的集合,单列集合,默认类型为object类型,使用前尽量知名类型,以免后期转换出现问题。
List接口
ArrayList: 它的底层是由数组来进行存储的,存储区域是连续的一块空间,默认大小是10,它可以自动扩容,每次扩容后都是原来的1.5倍。可以存放重复元素,扩容时采用的时Arrays.copyOf()方法进行拷贝,拷贝之后原来的数组没有指向,很快就会倍垃圾回收期回收掉
private static final int DEFAULT_CAPACITY = 10;//数组默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};// 传零的时候定义的
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定义一个空数组,跟前面的区别就是这个空数组是用来判断ArrayList第一添加数据的时候要扩容多少。默认的构造器情况下返回这个空数组 无参构造出来的
transient Object[] elementData;//数据存的地方它的容量就是这个数组的长度,同时只要是使用默认构造器(DEFAULTCAPACITY_EMPTY_ELEMENTDATA )第一次添加数据的时候容量扩容为DEFAULT_CAPACITY = 10 ,当前arraylist对象底层的数组地址。
private int size;//当前数组的长度
默认使用的是第二种
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
在创建时不指定容量的情况下,会返回一个长度为零的空数组,在调用add方法时,才触发扩容机制
当数组的大小大于原来的容量时,会触发扩容机制。
扩容机制
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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:
elementData = Arrays.copyOf(elementData, newCapacity);
}
1.如果链表是由默认的方法来创建的,那么它最开始返回的是一个长度为零的空数组,此时数组的容量才会从零扩容成10,而后的容量才是按当前的1.5倍进行扩容的。
为啥扩容的是1.5倍呢?
int newCapacity = oldCapacity + (oldCapacity >> 1);
由扩容中的此行代码可以看出,它的新容量=旧容量+就容量右移一位(底层是二进制,右移一位相当于原来的大小除以2)因此可以看出它扩容后大容量是原来的1.5倍。(底层实现都是二进制位运算),因此啊(23除2的值为11)
而addAll的方法中,扩容机制有一些变化:
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCo