Java从入门到放弃(六)集合框架之ArrayList源码(2)
2018-04-03 22:58
441 查看
上一篇文章Java从入门到放弃(五)集合框架之ArrayList(1)介绍了ArrayList的构造方法和add方法。对于随机插入,ArrayList是把要插入位置后面的元素全部后移,然后把元素插入到指定位置,如果集合内元素比较多的时候,如1000个元素,你要在5这个位置插入一个元素,就要把5后面的994个元素全部都后移一格,很消耗性能。
看一下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的最大值。
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方法
6、isEmpty,clear,size
return size == 0;
}isEmpty很简单,就是判断size是否为0,
size方法就是返回size属性
size和length的区别:size是集合内元素的个数,length是集合内数组的长度,如添加第一个元素后,size的值为1,而length的值是10;
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从入门到放弃(五)集合框架之ArrayList源码(1)
- Java从入门到放弃(七)集合框架之ArrayList的坑
- Java 集合框架源码分析(一)——ArrayList
- java源码分析之集合框架 ArrayList 03
- Java 集合框架源码分析(一)——ArrayList
- 【Java8源码分析】集合框架-ArrayList
- java核心之集合框架——ArrayList源码分析
- Java 集合框架03---ArrayList的源码分析
- java源码分析之集合框架 ArrayList和LinkedList的区别05
- JavaSE入门学习35:Java集合框架之List接口及其实现类ArrayList和LinkedList
- Java 集合框架 ArrayList 源码剖析
- java_集合体系之Collection框架相关抽象类接口详解、源码——02
- java_集合体系之ArrayList详解、源码及示例——03
- Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例
- Java基础---集合框架---迭代器、ListIterator、Vector中枚举、LinkedList、ArrayList、HashSet、TreeSet、二叉树、Comparator
- 【Java集合源码剖析】ArrayList源码剖析
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- 【Java集合源码剖析】ArrayList源码剖析
- 集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)
- java_集合体系之Map框架相关抽象类接口详解、源码——08