18_Java集合ArrayList
作者:互联网
ArrayList 集合可以理解为 存储引用类型元素 的数据容器,元素类型不限,但可以通过 指定类型参数 限制可以存储的数据类型。
常用方法
- 增添元素
// 在末尾添加元素
public boolean add(E e)
// 在指定位置插入元素
public void add(int index, E element)
- 删除元素
// 删除指定元素,只删除第一个相同的元素
public boolean remove(Object o)
// 删除指定索引的元素
public E remove(int index)
// 删除所有元素
public void clear()
- 修改元素
// 修改指定索引的元素
public E set(int index, E e)
- 查找元素
// 顺序查找,返回元素索引位置
public int indexOf(Object o)
// 倒序查找,返回元素索引位置
public int lastIndexOf(Object o)
// 是否包含指定元素
public boolean contains(Object o)
- 访问元素
// 访问指定索引处的元素
public E get(int index)
- 获取元素个数
// 获取容器中的元素个数
public int size()
基本原理
transient Object[] elementData; // 存放元素
private int size; // 记录存放的元素个数
protected transient int modCount = 0; // 父类 AbstractList 中,记录修改次数
ArrayList 是基于数组实现的,Object 数组 elementData 存放元素,变量 size 记录实际存放的元素个数,modCount 记录修改次数,每次发生结构性变化的时候 modCount 都会增加。
- add 方法
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 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;
}
迭代遍历
- 普通循环遍历
可以使用 while、for 循环对 ArrayList 集合进行遍历。
- foreach 迭代遍历
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
for (Integer ele: arrayList) {
System.out.println(ele);
}
编译器会对 foreach 语法进行转换。
while(arrayList.hasNext()){
System.out.println(arrayList.next());
}
ArrayList 实现了 Iterable 接口,Iterable 表示可迭代,只要实现了 Iterable 接口,就可以使用 foreach 语法。
public interface Iterable<T> {
Iterator<T> iterator();
}
iterator 方法返回一个实现了 Iterator 接口的对象。
public interface Iterator<E> {
boolean hasNext(); // 判断是否还有元素可访问
E next(); // 返回下一个元素
default void remove() { // 删除最后返回的元素
throw new UnsupportedOperationException("remove");
}
}
来看 ArrayList 中的 iterator:
public Iterator<E> iterator() {
return new Itr();
}
// Itr 是内部类
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; // 每次发生结构性变化的时候 modCount 都会增加
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
注意迭代中的删除:
/**
* foreach 遍历时不能直接调用 remove 方法进行删除
* 因为 foreach 实际是调用 Iterator 的方法,迭代器遍历时会维护索引位置相关的数据
* 直接 remove 会导致结构变化,导致索引数据失效
*/
for (Integer ele: arrayList) {
if(ele == 2) arrayList.remove(ele); // 执行报错
System.out.println(ele);
}
使用迭代器删除:
Iterator<Integer> it = arrayList.iterator();
while (it.hasNext()){
if(it.next() == 2) it.remove();
}
实现接口
- Collection
Collection 表示一个数据集合,数据没有位置或顺序的概念。
- List
List 表示有顺序或位置的数据集合,主要方法都与位置有关。
- RandomAccess
标记接口,RandomAccess 表示可以随机访问,数据在内存是连续存放的,根据索引值可以直接定位到具体的元素,访问效率很高。
主要特点
- 只能存放引用类型数据
- 底层结构是数组,增删慢,查询相对较快,数据在内存连续存放,可以根据索引随机快速访问
- 线程不安全
标签:elementData,Java,int,18,ArrayList,元素,minCapacity,public 来源: https://www.cnblogs.com/knhap/p/16353963.html