1.概念--什么是ArrayList
ArrayList 是 java 集合框架中比较常用的数据结构。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许数据为空(null)。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。
2.简单应用--ArrayList的使用
//指定类型
ArrayList list1 = new ArrayList();
list1.add("aa");
//Object类型
ArrayList arrayList = new ArrayList();
arrayList.add(12); //直接添加一个Object元素
arrayList.add(0,"cc");//指定下标,添加一个Object元素
arrayList.add(1,0.5f);//指定下标,添加一个Object元素
3.ArrayList的架构--方法以及属性的含义(列举接触的部分)
3.1重要成员变量
private static final int DEFAULT_CAPACITY = 10; //默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};//用于存储空实例但是内容为空的实例的对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//将其与EMPTY_ELEMENTDATA区分开来,以了解在添加第一个元素时应该膨胀多少
transient Object[] elementData; //存储数组的数据,transient不可序列化,此处没必要,节省空间
private int size; //数组大小
3.2构造器--构建怎样的ArrayList
public ArrayList() { //无参构造器 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//默认没空--即解释了为何ArrayList可以为空 }
public ArrayList(int initialCapacity) {....}//构造一个自定义初始容量的空ArrayList
public ArrayList(Collection c) {//构造一个以集合为参数的ArrayList elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray 可能不会正确地返回一个Object数组 //因为传进来的集合参数,在参数是 ArrayList集合,以及Arrays.asList()集合时,toArray()方法没有进行Object[]转换,还是开始时指定的类型,如:ArrayList
.... if (elementData.getClass() != Object[].class) //其他种类的集合都强行转换成了Object[] //Arrays.copyOf则会返回一个object[].class类型,大小为size,元素为elementData[...]的数组 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; } }
3.3 列举几个常见的方法:add,addAll,remove,get,set,size,isEmpety,contains,indexOf
add方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将源数组src,index位置往后size-index个数据copy到目标数组dest从index+1的位置开始,相当于往后推了一位,留了个index的空位
System.arraycopy(src:elementData, srcPos:index, dest:elementData, destPos:index + 1,length:size - index);
elementData[index] = element;//往index处添加参数element
size++;
}
public boolean addAll(Collection c) {
//拿到所有的集合值转为object数组
Object[] a = c.toArray();
int numNew = a.length;
//扩容,包装数组大小超过size+numNew
ensureCapacityInternal(size + numNew); // Increments modCount
//实现数组的复制
//参数列表:1.源数组 2.起始位置 3.目的数组 4.目的数组的起始位置 5. 源数组被copy的长度
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
//如果长度为空返回false,否则为true
return numNew != 0;
}
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);//拿到当前index位置的值
//对应下面copy的length,保证每次都是从index(包含)开始到最后一位的数据被copy,因为下标从零开始,多减一
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;
}
3.4扩容机制
private void ensureCapacityInternal(int minCapacity) { //对应上面add方法中的方法。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //记录修改次数
//最小的容量大于当前的size,则OK
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) { //核心方法
//当前的size
int oldCapacity = elementData.length;
//按位右移(除以2的1次方),相当于扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//新的容量还是小于需要的容量,则将需要的容量设置为新容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//newCapacity溢出,
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);
}//直接传值设定list容量方法
public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA): DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
3.5fail-fast机制(快速失败)--以及ArrayList的遍历和排序--3种
概念:是一种自我保护机制,防止多个进程进入同一个list中操作数据。当正在迭代遍历一个list时,别的进程进入当前list操作的话,则会报错ConcurrentModificationException。(该机制发生在与快速失败的迭代器有关的时候,java.util包下面的所有的集合类都是快速失败的)。
public Iterator iterator() {return new Itr();}
spliterator();
forEach(Consumer action);
private class Itr implements Iterator {
int cursor; // 下一个要返回的索引,默认为0
int lastRet = -1; // 返回的最后一个元素的索引;如果没有,则返回-1,默认0
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
...省略
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 consumer) {
...省略
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
解决方法:fail-fast机制,是一种错误检测机制。它只能被用来检测错误,因为JDK并不保证fail-fast机制一定会发生。若在多线程环境下使用fail-fast机制的集合,建议使用“java.util.concurrent包下的类”去取代“java.util包下的类”。
将ArrayList 替换为 :
Listlist = new CopyOnWriteArrayList ();
参考博客:https://www.cnblogs.com/shamo89/p/6685216.html
3.foreach使用:
@Override
public void forEach(Consumer action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
List
temp = new ArrayList (); ----列举了4种foreach的方式 for(int i=0;i<5;i++) temp.add("a" + i); for (String aa: temp) { //1.7及之前 同理之前的iterator,在执行第二次时报错 temp.add(aa); } temp.forEach(cc -> System.out.println(cc)); //1.8lambda表达式 System.out.println("------------"); temp.forEach(mystr -> { //1.8 可引用{}及return if(temp.size() == 5){ System.out.println(mystr); } }); System.out.println("------------"); temp.forEach(new Consumer () { //1.8 结合匿名内部类 @Override public void accept(String s) { if(temp.size() == 5){ System.out.println(s); } } });
4. spliterator
参考博客:https://www.cnblogs.com/nevermorewang/p/9368431.html
ArrayList:底层数据结构是Array,有序的、可重复的、允许数据为null、支持快速访问、非安全的(不同步)、可动态扩容的集合类。