属性
/**
* serialVersionUID-序列化的版本号
* DEFAULT_CAPACITY-默认容量
* EMPTY_ELEMENTDATA-是一个Object类型的数组
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA-同上面的一样
* elementData-是一个缓存数组
* size数组中元素的数量
*/
三个构造方法
分别为:指定大小初始化、无参初始化(默认)、指定初始数据初始化。
//指定大小初始化构造放啊
public ArrayList(int initialCapacity) {//initialCapacity=指定容量大小
if (initialCapacity > 0) {
//elementData 是保存数组的容器,默认为 null
//new一个object数组,赋给elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {//等同于无参初始化构造方法
//一个空数组,赋给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {//小于0抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//无参初始化(默认)构造方法
public ArrayList() {
//一个空数组,赋给elementData
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//指定初始数据初始化构造方法
public ArrayList(Collection<? extends E> c) {
//toArray()是构造一个object数组,然后进行数据拷贝,如果此时转型则会抛出ClassCastException异常
Object[] a = c.toArray();
//如果给定的集合(c)数据有值
if ((size = a.length) != 0) {//size=0
//判断c集合元素类型是否等于ArrayList,等与就直接赋值,集合元素类型不是 Object 类型,我们会转成 Object
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
//等同于无参初始化构造方法
elementData = EMPTY_ELEMENTDATA;
}
}
Add(object o)方法
主要分两部
1、判断需不需要扩容,需要则执行扩容操作
2、直接赋值
总结
1、扩容后=扩容前1.5倍
2、数组溢出意思:数组容量最小不能小于0,最大不能大于Integer 的最大值
3、并发时ArrayList时不安全的:因为他只是简单的赋值,并没有添加安全操作
4、扩容是判断添加该元素后,数组容量是否>之前数组默认容量,不大于,不进行扩容,大于,进行扩容,并且在扩容后还要判断:新数组容量是否>旧数组容量,大于则不扩容,不大于则扩容
注意
1、mount解释为数组修改次数
ArrayList<Object> arrayList = new ArrayList<>(10);//注意这里给集合初始化容量=10
for (int i=0;i<=10;i++){
arrayList.add(i);
}
public boolean add(E e) {
//确保数组大小是否足够,不够执行扩容,size 为当前数组的大小
ensureCapacityInternal(size + 1); //size=0
//直接赋值,线程不安全的
elementData[size++] = e;
//直接返回true,说明执行add方法一定会成功
return true;
}
private void ensureCapacityInternal(int minCapacity) { //minCapacity=1
//elementData是object数组引用,minCapacity=1
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断缓存数组大小是否相等默认空数组容量:第一次添加元素肯定相等,成功添加元素后就不会相等了
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY默认=10
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
//记录数组被修改,此阶段没啥用
modCount++;
//判断需不需要扩容:add执行后大于现有的数组的长度,则执行扩容,反之则直接赋值
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//二进制位运算(oldCapacity >> 1)
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果扩容后的值 > jvm 所能分配的数组的最大值,,那么就用 Integer 的最大值,并且JVM就不会给数组分配内存了
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//这里应该是关于拷贝的事
elementData = Arrays.copyOf(elementData, newCapacity);//扩容:将原来的数组中的数据克隆到新数组中,并且缓存数组容量也扩大1.5倍
}
迭代器—Iterator
ArrayList<Object> arrayList = new ArrayList<>(10);//注意这里给集合初始化容量=10
for (int i=0;i<=10;i++){
arrayList.add(i);
}
//判断arrayList是否还存在元素A
arrayList.iterator().hashNext()
//取出元素A
arrayList.iterator().next()
//移除元素A
arrayList.iterator()remove()
//实例
Iterator<Integer> iterator = arrayList.iterator();
for (int i = 0; i < arrayList.size(); i++) {
if (iterator.hasNext()){
System.out.print(iterator.next());
}
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // 迭代过程中,下一个元素的位置,默认从 0 开始
int lastRet = -1;
int expectedModCount = modCount;// expectedModCount 表示迭代过程中,期望的版本号
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification()//判断 期待版本号与 modCount 是否相同
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) {
//具体实现省略
}
//判断 期待版本号与 modCount 是否相同
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
remove(object o)删除
删除元素有很多种方式,比如根据数组索引,根据值删除,根据集合删除等等,其实思路都差不多,下面选取根据值删除
思路:判断是否等于null,不等于null后判断数组中是否有该值,有着删除,并且将删除后的数组向前移位。数组中无删除的值则直接返回。
ArrayList<Object> arrayList = new ArrayList<>(10);
arrayList.add("asd");
arrayList.remove("asd");
public boolean remove(Object o) {//0=""asd
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) {//index=0
modCount++;
// numMoved 表示删除 index 位置的元素后,需要从 index 后移动多少个元素到前面去
int numMoved = size - index - 1;//size=数组元素数量
if (numMoved > 0)
// index+1表示从 index +1 位置开始被拷贝,拷贝的起始位置是 index,长度是 numMoved
System.arraycopy(elementData, index+1, elementData, index,numMoved);
//数组最后一个位置赋值 null
elementData[--size] = null; // 清除以让GC完成它的工作
}
get(int index)方法
简单
public E get(int index) {
//判断index是否在这个范围[0,size)
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
set(int index, E element)方法
在指定位置修改元素,注意不是 “ 添加 ” 是 “ 修改 ”
public E set(int index, E element) {
//判断index是否在这个范围[0,size)
rangeCheck(index);
E oldValue = elementData(index);
//修改index索引处的值=element
elementData[index] = element;
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}