List_ArrayList
1.ArrayList的特点
- 内部是通过数组实现的,
- 支持随机访问
- 数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。
- 当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进 行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
- 线程不安全
- 容量不够时
2.ArrayList构造函数
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
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 = {};
transient Object[] elementData;//用数组来村南方各种存放数据,elementData.length 可以存放的元素个数
private int size;//实中元素的少数
2.1 public ArrayList()
/**
* Constructs an empty list with an initial capacity of ten.
* 初始值为10 如果,new ArrayList()没有赋值时默认长度为10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2.2 public ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];//如果指定new ArrayList(len)的初始长度大于0.则直接生成这个长度的object数组
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;//如果初始为0则为空{}
} else {//如果指定的初始容量长度<0,则抛出数字不合法异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
2.3public ArrayList(Collection<? extends E> c)
- 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表
- 如果集合长度为0则为{}
3.ArrayList常用方法
3.1 add()
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)//如果插入元素此时的list的元素个数等于了数组的长度,则进行扩容操作
elementData = grow();//扩容
elementData[s] = e;//并把元素增加到最后一个元素后面
size = s + 1;
}
public boolean add(E e) {
modCount++;//modCount记录操作次数
add(e, elementData, size);
return true;
}
public void add(int index, E element) {//表示在第几个位置插入元素
rangeCheckForAdd(index);//如果插入的位置>size||<0则抛出异常
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)//如果要插入的元素刚好等于容易可以容纳的长度 则进行扩容
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);//这个native了,大概意思可能是让原来的ArrayList的index前半部分,index后半部分装在新的扩容的数组里面,index位置有一个空位置,留给e
elementData[index] = element;
size = s + 1;
}
3.2 那来谈谈扩容吧 grow()
public void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private Object[] grow() {
return grow(size + 1);
}
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);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)//如果扩容后的容量比最大容量大,则
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)//如果扩容1.5倍之后太大则,
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
3.3 public E remove(int index)
public E remove(int index) {
Objects.checkIndex(index, size);//查看要remmove的元素的下标是否符合要求
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
public boolean remove(Object o) {//判断是否可以remove
final Object[] es = elementData;
final int size = this.size;
int i = 0;
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)//如果为true说明要删除的不是最后一个元素,而是中间的位置元素
System.arraycopy(es, i + 1, es, i, newSize - i);//把index+1的后面所有元素向前移动一位
//es:原元素集合
//i + 1 开始的位置
//es复制到的目标元素
//i 目标元素的开始位置
//newSize - i 以及复制的长度
es[size = newSize] = null;//把之前最后一个元素1的位置值为null,
}
3.4 get
set
- 因为底层使用数组来实现,所以 底层直接通过[index]的方式获取和设置值,这里不阐述
3.5 equals
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof List)) {
return false;
}
final int expectedModCount = modCount;//mpdCount对ArrayList的操作
boolean equal = (o.getClass() == ArrayList.class)
? equalsArrayList((ArrayList<?>) o)
: equalsRange((List<?>) o, 0, size);
checkForComodification(expectedModCount);
return equal;
}
boolean equalsRange(List<?> other, int from, int to) {
final Object[] es = elementData;
if (to > es.length) {
throw new ConcurrentModificationException();
}
var oit = other.iterator();
for (; from < to; from++) {
if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
return false;
}
}
return !oit.hasNext();
}
private boolean equalsArrayList(ArrayList<?> other) {
final int otherModCount = other.modCount;
final int s = size;
boolean equal;
if (equal = (s == other.size)) {
final Object[] otherEs = other.elementData;
final Object[] es = elementData;
if (s > es.length || s > otherEs.length) {
throw new ConcurrentModificationException();
}
for (int i = 0; i < s; i++) {
if (!Objects.equals(es[i], otherEs[i])) {
equal = false;
break;
}
}
}
other.checkForComodification(otherModCount);
return equal;
}
如果两个地址相同返回true,入托不属于List的一个实例则直接返回false
如果输入类型ArrayList
如果size一样且a.equals(b) a.size的长度不大于b的size,&& 对比每一个元素,如果符合,他们的操作次数,如果都符合则true,有一个不满足都抱错或者false
如果输入的类型为list
调用equalsRange方法 使用迭代器 一一对比
3.6 public ListIterator<E> listIterator(int index)
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
// prevent creating a synthetic constructor
Itr() {}
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();
}
}
-
hasNext 实现比较简单,如果下一个元素的下标等于集合的大小 ,就证明到最后了。
-
next 方法也不复杂,但很关键。首先判断
expectedModCount 和 modCount
是否相等。然后对cursor
进行判断,看是否超过集合大小和数组长度。然后将cursor
赋值给lastRet
,并返回下标为 lastRet 的元素。最后将cursor
自增 1。开始时,cursor = 0,lastRet = -1;每调用一次 next 方法, cursor 和 lastRet 都会自增 1。 -
remove 方法首先会判断
lastRet
的值是否小于 0,然后在检查expectedModCount
和modCount
是否相等。接下来是关键,直接调用ArrayList
的remove
方法删除下标为 lastRet 的元素。然后将lastRet
赋值给cursor
,将lastRet
重新赋值为 -1,并将modCount
重新赋值给expectedModCount
。