您的位置:首页 > 编程语言 > Java开发

Java从入门到放弃(六)集合框架之ArrayList源码(2)

2018-04-03 22:58 441 查看
       上一篇文章Java从入门到放弃(五)集合框架之ArrayList(1)介绍了ArrayList的构造方法和add方法。对于随机插入,ArrayList是把要插入位置后面的元素全部后移,然后把元素插入到指定位置,如果集合内元素比较多的时候,如1000个元素,你要在5这个位置插入一个元素,就要把5后面的994个元素全部都后移一格,很消耗性能。

3、扩容方法

private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
插入一个元素最少需要size+1长度的数组,所以grow(size+1),然后调用了Arrays.copyof函数,第一个参数是原始数组,第二个参数是新数组的长度。
看一下newCapcity函数private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; //原始数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1); 新数组长度为原数组的1.5倍,
if (newCapacity - minCapacity <= 0) { 如果新数组长度小于所要求的最小数组长度值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 数组是默认的空集合
return Math.max(DEFAULT_CAPACITY, minCapacity); 返回默认数组长度和最小长度的最大值,默认长度值为10
if (minCapacity < 0) // overflow 参数小于0,抛出异常
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0) //MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
? newCapacity
: hugeCapacity(minCapacity);
}ArrayList的扩容是1.5倍,在第一个元素插入时会把数组长度设为默认的10,12行是判断数组长度是否大于最大值,最大值为Int值的最大值减去8,即2^31-9,如果小于扩容1.5倍,大于的话就返回Int的最大值。

4、remove

public E remove(int index) {
Objects.checkIndex(index, size);  //如果index大于size抛出异常

modCount++;                       //修改次数增加
E oldValue = elementData(index);  //获取数组index位置的元素

int numMoved = size - index - 1;  //要移动元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);

//把index后面的元素都往前移一个位置,即elementData中index+1
//后面的numMoved个元素移动到elementData中以index开始的位置
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}
remove和add方法类似,移除是把移除元素后面的全部元素往前移动一个位置,然后返回删除的值。public boolean remove(Object o) {
if (o == null) { //如果删除null值
for (int index = 0; index < size; index++) //循环查找数组元素删除
if (elementData[index] == null) {
fastRemove(index); //删除index位置的元素
return true;
}
} else {
for (int index = 0; index < size; index++) //循环查找数组元素,
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}就是循环遍历对比删除指定元素,因为null和null不相等,所以分了两种情况。可以看到ArrayList是通过equals对比来删除指定元素的,所以如果要用到这个方法最好重写equals和hashcode方法,具体可参考Java从入门到放弃(三)equals和==
看一下fastRemove方法: private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work 赋值为null,让回收器回收。
}其实就是和remove(int)方法一样,少了一步越界检查,因为在上面的方法里面已经保证了不会出现越界。remove和add方法一样比较耗性能,因为要移动指定元素后面所有的元素。
5、set,get方法
public E set(int index, E element) {
Objects.checkIndex(index, size);  //索引越界检查
E oldValue = elementData(index);  //取出旧值
elementData[index] = element;     //赋值新值
return oldValue;
}
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
set和get方法都是比较的简单的方法,就是检查索引越界然后执行对于的操作。
6、isEmpty,clear,size

public void clear() {
modCount++;
final Object[] es = elementData;
for (int to = size, i = size = 0; i < to; i++)
es[i] = null;
}
clear并不是删除所有的元素,而是把size置为0,然后把elementData的元素都设为null,这样子可以在GC的时候被回收。public boolean isEmpty() {
return size == 0;
}isEmpty很简单,就是判断size是否为0,
size方法就是返回size属性
size和length的区别:size是集合内元素的个数,length是集合内数组的长度,如添加第一个元素后,size的值为1,而length的值是10;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java