JDK源码分析(1)-java.util.ArrayList
2016-10-25 20:55
585 查看
1. 前言
从Mybatis开始,看源码这种学习方式似乎给了我一个新的大门,可惜的是看Mybatis时并没有深入看,现在又忘了七七八八,也算一个教训,以后还是得认真写博客。ArrayList几乎是我们在写代码中用的最多的Collection实现,一直想尝试看看JDK源码,对于一些集合的基本知识不在本篇中再叙述。现在开始撸源码吧。
2. 分析
//默认初始容量 private static final int DEFAULT_CAPACITY = 10; //保存数据的数组 transient Object[] elementData; //表示一个空的数组 private static final Object[] EMPTY_ELEMENTDATA = {}; //表示使用默认的初始化容量 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //这两个数组都是在添加第一个元素之前,用来标识用的 //当前节点数 private int size; //================三种构造函数================== //空构造函数 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //代初始化容量的构造函数 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //如果参数大于零就初始化这么大的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //初始值为0,先指向一个空数组 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } public ArrayList(Collection<? extends E> c) { //直接把传入集合的数组传给elementData elementData = c.toArray(); if ((size = elementData.length) != 0) { // toArray()可能不返回数组 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 为空就先指向一个空数组 this.elementData = EMPTY_ELEMENTDATA; } } //缩减数组到和实际长度相同大小 public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } //确保当前容量 public void ensureCapacity(int minCapacity) { //如果不是默认的就先为0,否则就设置为默认初始容量 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; //如果当前元素数大于容量则扩容 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } //扩容 private void ensureCapacityInternal(int minCapacity) { // 初始化 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } //更新容量 private void ensureExplicitCapacity(int minCapacity) { modCount++; // 防止溢出 if (minCapacity - elementData.length > 0) grow(minCapacity); } //增长 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); } //扩大容量 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //如果大于最大容量则设置为整数最大容量,否则设置为数组最大容量 //整数最大容量是数组最大容量-8 = = 为什么呢? return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } //返回当前元素数 public int size() { return size; } //元素是否为空 public boolean isEmpty() { return size == 0; } //判断是否含有某个元素,是先获取当前元素的索引,然后判断索引是否大于0 public boolean contains(Object o) { return indexOf(o) >= 0; } //获取当前元素的索引 public int indexOf(Object o) { //如果为null直接遍历判断是否为null元素 if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { //不为空则用equals()方法来判断是否含有此元素 for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } //都找不到则返回-1 return -1; } //找元素的最后一个索引 public int lastIndexOf(Object o) { // 总的来说就是反着找 if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; } //克隆方法 public Object clone() { try { //调用父类的clone方法,并将当前的数据copy一份给clone后的对象 ArrayList<?> v = (ArrayList<?>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } } //转化为数组 public Object[] toArray() { return Arrays.copyOf(elementData, size); } //检测是否越界 private void rangeCheck(int index) { if (index >= size) //越界则抛出IndexOutOfBoundsException异常 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } //获取一个元素 public E get(int index) { //先判断是否越界 rangeCheck(index); return elementData(index); } //设置一个元素到某个位置 public E set(int index, E element) { //验证越界 rangeCheck(index); //把新元素覆盖老元素,并返回老元素 E oldValue = elementData(index); elementData[index] = element; return oldValue; } //新增一个元素 public boolean add(E e) { //查看是否需要增长 ensureCapacityInternal(size + 1); // Increments modCount!! //修改,成功返回true elementData[size++] = e; return true; } //插入一个元素 public void add(int index, E element) { //越界检查 rangeCheckForAdd(index); //增长检查 ensureCapacityInternal(size + 1); // Increments modCount!! //直接调用System.arraycopy()留出一个空位 System.arraycopy(elementData, index, elementData, index + 1, size - index); //赋值 elementData[index] = element; size++; } //删除一个指定位置的元素 public E remove(int index) { //越界检测 rangeCheck(index); modCount++; E oldValue = elementData(index); //移动的节点处 int numMoved = size - index - 1; //直接调用System.arraycopy()方法右移覆盖 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //将最后多出一个置null elementData[--size] = null; // clear to let GC do its work //返回被删除的元素 return oldValue; } //删除一个元素,由于找到后肯定不会越界所以直接调用快速删除 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; } //快速删除,不检查越界也不返回被删元素 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 } //清除所有元素 public void clear() { modCount++; // 遍历置null for (int i = 0; i < size; i++) elementData[i] = null; //设置元素个数为0 size = 0; } //返回一个迭代器 public Iterator<E> iterator() { return new Itr(); }
2.1 迭代器与fail-fast机制
在之前的所有对元素的修改操作中,都会使modCount+1,这就是fail-fast机制。fail-fast机制是为了检测因并发修改而导致的程序bug。private class Itr implements Iterator<E> { int cursor; // 下一个元素的索引 int lastRet = -1; // 最后一个元素的索引 int expectedModCount = modCount; //直接判断下一个索引是否为总数 public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { //检查是否有修改 checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; //可能出现了修改 if (i >= elementData.length) throw new ConcurrentModificationException(); //继续指向下个索引 cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); //检查是否有修改 checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } //检查是否有修改 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
大概就这些,有空再分析一下foreach的实现!
参考资料:
http://blog.csdn.net/ns_code/article/details/35568011
http://blog.csdn.net/chenssy/article/details/38151189
相关文章推荐
- JDK源码分析之java.util.ArrayList
- (7) java源码分析------之ArrayList (对应数据结构中线性表中的顺序表,JDK1.6)
- java基础提高篇--集合源码分析--jdk1.8 ArrayList源码
- JDK源码分析——Java.util.Vector的浅析
- JDK源码分析——Java.util.Vector的浅析
- java容器源码分析--ArrayList(JDK1.8)
- Java容器深入研究(jdk 1.8)--- ArrayList总结与源码分析
- Java Collections Framework之ArrayList源码分析(基于JDK1.6)
- JDK源码学习(3)-java.util.ArrayList与LinkedList
- JDK源码分析(2)-java.util.LinkedList
- Java -- 基于JDK1.8的ArrayList源码分析
- JDK(二)java源码分析之ArrayList
- java.util.ArrayList 实例推动源码分析
- Java中ArrayList源码深入分析(JDK1.6)
- java核心基础--jdk源码分析学习--ArrayList
- java学习之旅59--模拟ArrayList容器的底层实现_JDK源码分析ArrayList
- Java源码解读之util.ArrayList .
- JDK源码分析:java.lang.String
- Java源码解读之java.util.ArrayList
- Java Collections Framework之ArrayList源码分析