ArrayList源码分析(JDK1.8)

mac2024-07-23  59

说明:源码大概有1461行,其实没这么复杂,java基础过关还是能看懂的,下面我讲解到的函数,直接把需要用到的其他函数从源码分离出来,方便好分析


目录

成员变量

初始化

添加

获取

设置元素

删除

查找


成员变量

private static final long serialVersionUID = 8683452581122892189L;//序列化会用到的,我们不用关心它 private static final int DEFAULT_CAPACITY = 10;//这是一个默认容量,初次加入新的元素,数组会初始化容量为默认容量 private static final Object[] EMPTY_ELEMENTDATA = {};//这是一个空数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//这是一个默认容量为0的空数组 transient Object[] elementData; //我们添加的元素都会放着这个数组里边 private int size;//我们每添加一个新的元素,这个都会自增加一,可以理解为保存数组的个数

这是ArrayList的成员变量,elementData和size才是我们要关心的对象

初始化

ArrayList有三个构造函数

public ArrayList()public ArrayList(int initialCapacity)public ArrayList(Collection<? extends E> c)

默认构造函数

public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }

elementData:这是一个元素数组

DEFAULTCAPACITY_EMPTY_ELEMENTDATA:看常量名可以理解这是一个默认容量空元素数组

指定容量初始化

public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }

如果initialCapacity大于0,将会创建一个大小为Object数组,赋值给elementData

如果initialCapacity等于0,elementData将被赋值为空元素数组

如果initialCapacity小于0,抛出IllegalArgumentException异常,非法容量

使用集合初始化

public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }

集合c转化为数组赋值给elementData

将elementData的数组大小赋值给size

如果size不等于0并且数组不是Object数组,将该数组转化为Object数组重新赋值给elementData

如果集合c大小为0,elementData赋值为空元素数组

添加

public boolean add(E e)public void add(int index, E element)public boolean addAll(Collection<? extends E> c)public boolean addAll(int index, Collection<? extends E> c)

获取是否添加成功,当插入Integer.MAX_VALUE+1个元素返回false,否则返回true

public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code 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(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }

ensureCapacityInternal:确保数组容量足够使用,防止数组越界异常

grow:确定数组容量大小后,elementData将重新赋值为原来容量的1.5倍的新元素数组

oldCapacity>>1,这是位运算,结果与oldCapacity/2取整 相等

hugeCapacity:只有newCapacity大于Integer.MAX_VALUE-8时才会被调用

通过上面源码可以得知这里有个缺点,元素数组只能保存Integer.MAX_VALUE个元素,保存更多的元素就无能为力了,当保存Integer.MAX_VALUE+1个元素,将会抛出OutOfMemoryError,因为Integer.MAX_VALUE+1<0

在idnex处插入添加数据

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++; } private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }

rangeCheckForAdd:检查index合法性,当indx<0或index>size,抛出IndexOutOfBoundsException

添加过程如图

如果数组大小为10000,在第一个数据后边添加新的数据,第一个后边所有数据都需要依次往后边移动一步,效率不高

size++,元素个数加一

获取添加集合数据是否成功,当插入Integer.MAX_VALUE+1个元素返回false,否则返回true

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; }

将参数集合转化为Object数组

确保元素数组足够使用

使用arrayCopy,将Object数组添加到元素数组末尾

如果添加元素个数大于0返回true,否者false

获取在index插入添加集合数据是否成功,当插入Integer.MAX_VALUE+1个元素返回false,否则返回true

public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }

添加数据原理与public void add(int index, E element)相同,不同的是要插入的后边所有数据都要往后移动要添加数据的个数个单位

获取

public E get(int index)

获取index处的元素

public E get(int index) { rangeCheck(index); return elementData(index); } E elementData(int index) { return (E) elementData[index]; }

代码很容易理解的,检查index合法性,若合法返回elementData[index]

设置元素

public E set(int index, E element)\

设置index的元素值,返回被设置前的元素值

public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }

检查index的合法性

将elementData[idnex]赋值为element

删除

public E remove(int index)

public boolean remove(Object o)

public boolean removeAll(Collection<?> c)

删除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; } E elementData(int index) { return (E) elementData[index]; }

检验index的合法性

获取index处的元素

把index处后边所有元素向前移动一个单位,覆盖被删除的元素

size减一,且最后一个数组元素赋值为空

返回被删除的元素

返回删除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; } 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 }

如果o为null,删除第一个被查找找的null元素,返回true

如果不为null,删除第一查找找的o元素返回true

fastRemove:快速删除,把index处后边所有元素向前移动一个单位,覆盖被删除的元素

返回删除集合中的元素是否成功

public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); } public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; } public boolean contains(Object o) { return indexOf(o) >= 0; } 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; }

requireNonNull:判断参数集合元素是否为空,若空抛出NullPointerException

batchRemove:过程有点复杂,看图

contains:判断是否包含这个元素,依据元素位置是否非法来判断的,大于0合法,小于0非法

indexOf:返回元素的位置

查找

public int indexOf(Object o)public int lastIndexOf(Object o)

查找元素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; }

分三种情况

从数组的开头顺序往后查找

一:要查找的元素为空,且存在,返回元素为空的第一个位置

二:要查找的元素不为空,且存在,返回要查找元素的第一个位置

三:要查找的元素不存在,返回-1

返回最后出现的元素o的位置

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; }

分三种情况

从数组的末尾顺序往前查找

一:要查找的元素为空,且存在,返回元素为空的第一个位置

二:要查找的元素不为空,且存在,返回要查找元素的第一个位置

三:要查找的元素不存在,返回-1

其他

modeCount:来自于ArrayList的父类中的protected transient int modCount = 0;

在ArrayList添加删除元素时,这个modCount都会自增加一

他记录了这个列表在结构上的被修改次数,修改结构指的是改变列表的大小

 

 

 

 

 

 

 

 

 

最新回复(0)