本篇文章讨论以下几个问题
目录
ArrayList的初始化
1.无参构造 - ArrayList()
ArrayList arrayList = new ArrayList();
//ArrayList存放数据的数组
transient Object[] elementData; //空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //集合初始化一个空数组
}
构造函数有两个变量,这里我就可以得出:ArrayList的底层是由数组实现的,且我们没有给初始长度的时候默认给的是一个空数组;[空的怎么存数据??试试给个初始大小]
2.有参构造 - ArrayList(1)
ArrayList arrayList = new ArrayList(1);
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA; //还是个空数组
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
还是能传0的啊?add()加个数据试试,看看什么情况?
//新增数据
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! ??? 这干嘛的???
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//这里会有判断的啊,如果是空的就从 DEFAULT_CAPACITY, minCapacity 选个大的。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//private static final int DEFAULT_CAPACITY = 10; 这里才给个大小为10的啊。
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
关于初始数组为0,为啥也能添加的数据的过程已经get到了,下一个构造函数看看。
3.集合类参数 - ArrayList(Collection<? extends E> c)
参数说明:
Collection:集合的子类可以当做参数
<? extends E> :泛型,必须是E的子类
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();//将参数c(c是个数组)转换成数组
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)??这什么意思??
//c.toArray() 有坑??
if (elementData.getClass() != Object[].class)
//当真的出现 c.toArray() ,jdk 也做了处理方案。拷贝复制!!
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA; //这不就是相当于无参构造了嘛,弄了个寂寞
}
}
小小脑袋,大大的问号。不禁感慨自己太菜!!!
c.toArray()会有什么坑????[谁能告诉我?]
elementData.getClass()与Object[].class ,class 比较又是个什么玩意?(* ̄︶ ̄)
搁置疑问,接着看扩容吧... ...
动态扩容的过程
要想动态的扩容,肯定是在添加数据的时候。集合自己判断要不要扩容,去看看add咋搞的。
扩容吧小宝贝 - add(E e)
ensureCapacityInternal(size + 1) 似曾相识啊,初始化 为0的时候为啥能添加数据,刚刚看过。
private int size;//记录集合的实际存放的元素个数;
public boolean add(E e) {
//size+1 的目的:因为是添加元素,所以就要把当前数组的实际长度增加1
//看看是否超出了集合的当前容量
ensureCapacityInternal(size + 1); // Increments modCount!!
//当前存放数组元素个数+1
elementData[size++] = e;
return true;
}
来再看下 ensureCapacityInternal(int minCapacity)
private static final int DEFAULT_CAPACITY = 10;//默认容量10;
private void ensureCapacityInternal(int minCapacity) {
//如果当前数组是一个空数组的话,就取两个数的最大值。这里取得是容量10,当第一次使用add方法
//才去给数组一个固定的容量!可能是为了节约内存吧。脑壳疼。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//咳咳,去下面看这个方法的讲解
ensureExplicitCapacity(minCapacity);
}
老母猪戴胸罩,一套又一套 。来看这个tao~ ensureExplicitCapacity(minCapacity);
//来了,宝?
private void ensureExplicitCapacity(int minCapacity) {
//这个东西是记录,修改次数的。咱们这次就不管这个东西了
modCount++;
//不是从一开始就传进来一个size+1么?到这里才用上,到底扩不扩容就看这次的比较了
//当前实际大小+1之后大于了数组定义的长度,那肯定不行啊。妥妥的扩容
if (minCapacity - elementData.length > 0)
//下面去看扩容解释
grow(minCapacity);
}