源码学习之ArrayList
来源:互联网 发布:为什么黑人很懒 知乎 编辑:程序博客网 时间:2024/05/08 16:29
ArrayList源码分析学习
首先是ArrayList的定义
//继承AbstractList抽线类,实现了List、RandomAccess、Cloneable和Serializable接口public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList源码开头定义的几个成员变量
//表示ArrayList的默认容量为10,但是在我们初始化为一个空的ArrayList的时候容量并不是10,具体下文解释 private static final int DEFAULT_CAPACITY = 10; //表示空的一个元素数组,在初始化一个空的ArrayList的时候,elementData就等于这个EMPTY_ELEMENTDATA private static final Object[] EMPTY_ELEMENTDATA = {}; //这个就是实际存储数据的数组,从这个可以看出ArrayList是数组实现的 transient Object[] elementData; //这个就是数组列表的存储数据的size了 private int size;
构造函数,ArrayList一共提供了三个构造函数。
//第一个构造函数,参数initialCapacity为初始化容量,如果initialCapacity为负,则抛出IllegalArgumentException异常,否则就初始化elementData为一个大小为initialCapacity的数组public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); this.elementData = new Object[initialCapacity]; }//第二个构造函数,不传入参数,这个时候elementData,就设置成上文定义的空数组,EMPTY_ELEMENTDATA,这个时候数组链表的容量是0,并不是10.public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; }//第三个构造函数,传入参数为另一个集合。这个时候就是用传入集合的元素初始化数组链表。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); }
ArryList扩容机制
//保证容量,这块是外部手动调用扩容的。minCapacity是需要的最小容量。 public void ensureCapacity(int minCapacity) { //最小扩展,如果elementData等于EMPTY_ELEMENTDATA,那么minExpand设置为DEFAULT_CAPACITY,否则minExpand等于0 int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY; //如果最小需要容量大于最小扩展,那么这个时候需要保证最小需要容量的数值 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
//保证容量,这是内部函数调用用来扩容的,在每次添加元素的时候都会调用 private void ensureCapacityInternal(int minCapacity) { //elementData == EMPTY_ELEMENTDATA时,这个时候minCapacity去DEFAULT_CAPACITY和minCapacity大的一个。 //在初始化一个空的ArrayList时,elementData == EMPTY_ELEMENTDATA,这个时候添加一个元素,检查容量,minCapacity传递的是size+1,也就是1,这个时候minCapacity等于DEFAULT_CAPACITY。 if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
//上面两个函数调用的函数 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code //如果需要保证的最小容量大于elementData的长度,那么这个时候需要扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //具体的扩容函数 private void grow(int minCapacity) { int oldCapacity = elementData.length; //新容量,是原来的容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //如果新容量不能满足最小容量要求,那么新容量设置成minCapacity //从空添加一个元素的时候,minCapacity==DEFAULT_CAPACITY,这个时候容量就扩充到DEFAULT_CAPACITY了。 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果新容量大于MAX_ARRAY_SIZE,那么新容量设置成Integer.MAX_VALUE 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); }
//如果minCapacity大于MAX_ARRAY_SIZE,那么返回 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}
总结来说,扩容的机制是在每次添加元素的时候检查容量size+add_size,elementData是空数组的时候,容量会变成DEFAULT_CAPACITY,也就是10。elementData不是空数组的时候,如果size+add_size大于容量,也即是elementData.length,那么就扩容,扩容的方法是首先扩容1.5倍的原容量,然后判断1.5的原容量是否大于size+add_size,如果不大于,那么新容量设置成size+add_size,再检查size+add_size是否大于最大容量Integer.MAX_VALUE - 8,如果大于那么就设置成Integer.MAX_VALUE
ArrayList常用操作
size()
public int size() { return size; }
isEmpty()
public boolean isEmpty() { return size == 0; }
contains()
public boolean contains(Object o) { return indexOf(o) >= 0; }//找到elementData中第一次出现o的下标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;}
get()
public E get(int index) { //是否越界判断 rangeCheck(index); return elementData(index); }private void rangeCheck(int index) {if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}
set()
//修改下标index处的元素public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
add()
//在后面添加一个元素 public boolean add(E e) { //判断容量 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //在下标index处添加一个元素,有数据的移动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++;}
remove()
//删除下标为index的元素,需要后面的元素进行移动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; // clear to let GC do its work return oldValue; }//删除赌徒个等于o的元素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;}
clear
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
0 0
- 源码学习之ArrayList
- JDK源码学习之ArrayList
- 集合类学习之Arraylist 源码分析
- 集合类学习之Arraylist 源码分析
- Java集合之ArrayList源码概览学习
- JDK源码学习之Arraylist与LinkedList
- 透过源码学习集合框架之ArrayList
- java源码学习-----ArrayList
- java ArrayList源码学习
- JAVA源码学习-ArrayList
- java源码学习----ArrayList
- ArrayList源码学习
- ArrayList源码学习笔记
- ArrayList源码学习
- ArrayList源码学习
- ArrayList源码学习
- ArrayList源码学习
- 源码分析之ArrayList
- c++双链表
- pycurl和requests使用感受
- 用友U890 all in one 全套 资源下载地址
- Retrofit2.0中如何创建JSON所对应的javaBean
- erer
- 源码学习之ArrayList
- iOS CoreAnimation 基础动画CABasicAnimation
- 在window上添加subview更新keyviewloop(蓝色按钮,tab键切换)
- Redis报错:ERR Operation against a key holding the wrong kind of value 解决处理
- eclipse启动无响应,老是加载不了revert resources,或停留在Loading workbench状态
- java中的类(class),包(package),接口(interface)
- android shape的使用
- 制作根文件系统时的几个小问题
- YangMVC中的单例模式