关于集合的源码实现问题——ArrayList
来源:互联网 发布:美国看动漫的软件 编辑:程序博客网 时间:2024/06/08 01:24
集合是java里面很重要而且比较常用的工具,了解java集合的源码实现可以帮助我们更好的理解集合的底层实现原理。
两个私有属性的成员变量,一个是代表数组的elementData,另一个是数组的长度size
add方法数组长度加1,并且最后赋值为e,ensureCapacityInternal()方法应该是保证数组容量的,因为初始化的时候默认长度为10,我们继续来看
很好理解
下面看remove方法
先检查index位置的合法性,将后面的元素复制过来,将最后一个元素置为空,size减1
另一个重载方法
和 remove()差不多,少了index判断,因为既然找到了,就一定是合法的,而且,不返回移除元素
接下来看最后一个方法
通过阅读源码,将自己的成果进行记录以备以后复习用。
首先,毫无疑问,ArrayList底层是用数组实现的。我们来看代码:
private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size;
两个私有属性的成员变量,一个是代表数组的elementData,另一个是数组的长度size
我们先看构造方法:
public ArrayList(int initialCapacity) {//指定数组的大小 super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** *常用的构造方法,看来我们平时默认数组的大小为10 */ public ArrayList() { this(10); } public ArrayList(Collection<? extends E> c) {//当参数为集合时,将传入的集合返回给数组 elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }下面讨论比较常用的方法
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
add方法数组长度加1,并且最后赋值为e,ensureCapacityInternal()方法应该是保证数组容量的,因为初始化的时候默认长度为10,我们继续来看
private void ensureCapacityInternal(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }如果minCapacity大于数组容量了,该扩充了,好的,进入grow()方法
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); }先得到之前数组的容量,newCapacity容量为新数组的1.5倍,如果扩充后仍然小,将新数组容量设置为数组容量,这里又将新数组容量与允许的最大相比,如果比最大的还要大(其实不大可能),那就返回最大的
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }好的,add方法我们清楚了
下面add有一个重载函数
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
有了上面的分析,这段代码就明白多了,先扩容,将index位置起后面元素后移一位,将index位置放入指定元素。
addAll方法
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
很好理解
下面是index方法,先判断是否为空,说明里面可以存储空元素,然后非空判断,为什么不合并一起呢,说明 equals()方法后面不能是空元素
public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
下面看remove方法
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
先检查index位置的合法性,将后面的元素复制过来,将最后一个元素置为空,size减1
另一个重载方法
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }好理解了,可是为什么用了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; // Let gc do its work }
和 remove()差不多,少了index判断,因为既然找到了,就一定是合法的,而且,不返回移除元素
接下来看最后一个方法
public void trimToSize() { modCount++; int oldCapacity = elementData.length; if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } }因为之前数组被扩展,将有效元素重新复制到数组中,保证length和size相同,这样,也能节省空间。
其实还有方法没有分析完,但是常用的就是这么多了,有了上面的分析基础,其他也比较简单。
0 0
- 关于集合的源码实现问题——ArrayList
- Java集合—ArrayList的源码解读
- Java集合ArrayList实现原理——源码分析
- Java集合——ArrayList源码详解
- 集合框架源码学习——ArrayList
- 深入Java集合源码学习系列:ArrayList的实现原理
- java集合框架学习—ArrayList的实现原理
- 集合(1)—List接口的实现类ArrayList
- ArrayList的源码实现
- 集合之ArrayList实现源码分析
- 关于ArrayList的问题
- jdk1.8.0_45源码解读——ArrayList的实现
- jdk1.8.0_73源码解读——ArrayList的实现
- jdk1.8.0_45源码解读——ArrayList的实现
- 集合CSet的ArrayList实现
- java核心之集合框架——ArrayList源码分析
- java集合框架03——ArrayList和源码分析
- java集合框架03——ArrayList和源码分析
- sublime3 licence
- 浏览器详谈及其内部工作机制 —— web开发必读
- 客户端存储
- ACM-2007
- \R\rw1091
- 关于集合的源码实现问题——ArrayList
- B - 又见LKity
- 对于 包、类、对象的小结
- 方法可以返回局部变量的引用
- 排列生成器详解+实例 (C++实现)
- 0x01 什么是壳
- 面试题85:按指定精度打印开方后的结果
- Unix和Linux的的发展史
- solr概况