ArrayLisrt 应该不陌生,对,就是可调整大小的动态数组,具体怎么实现的呢,就让咱们一探究竟吧!
初始化:
构造方法:
构建一个初始化容量为10的空数组
//默认初始化数据容器
private static final Object[] EMPTY_ELEMENTDATA = {};/**
/* 存储数组元素的数组缓冲区
* ArrayList的容量就是这个数组缓冲区的长度
*任何一个空的ArrayList将在添加第一个扩展元素添加后,为默认容量
*/
transient Object[] elementData; // 非私有 简化嵌套类访问
public ArrayList() { this.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); } }
//构建一个包含指定集合的元素列表,
//将参数转为集合数组
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; } }
add():
将指定的元素添加到列表的末尾
/*
*
*@param e 新增数据元素
*
*/
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 void ensureExplicitCapacity(int minCapacity) {
modCount++;//集合的修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//返回数组最小容量,默认容量10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void grow(int minCapacity) {
//计算已有数组长度
int oldCapacity = elementData.length;
// >>:右移,相当于除以2的n次幂
// <<:左移,相当于乘以2的n次幂
//核心,扩容相当于原数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//赋值操作
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//拷贝操作
elementData = Arrays.copyOf(elementData, newCapacity);
}
add(int index, E element);
列表时指定位置插入指定元素
public void add(int index, E element) {
//校验新增索引位置 rangeCheckForAdd(index); //确认存储空间大,并扩容原大小1.5倍 ensureCapacityInternal(size + 1); // Increments modCount!!
//数组拷贝 System.arraycopy(elementData, index, elementData, index + 1,size - index); elementData[index] = element; size++; }
// 判断索引位置,大于数组大小或者小于0抛出异常
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
addAll(Collection<? extends E> c)
按照指定的集合的iterator返回的顺序将指定集合中的所有元素追加到列表末尾
public boolean addAll(Collection<? extends E> c) {
// 将新增的元素转化为数组 Object[] a = c.toArray();
// 获取数组a的长度 int numNew = a.length;
// 校验空间大小,并1.5倍扩容 ensureCapacityInternal(size + numNew); // Increments modCount
//拷贝元素 System.arraycopy(a, 0, elementData, size, numNew); //数组长度操作后,进行累加
size += numNew; return numNew != 0; }
addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到里列表,从指定的位置开始
public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount //计算需要移动的个数(elementData) int numMoved = size - index; if (numMoved > 0)//判断移动个数是否大于0 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
set(int index, E element)
修改方法
public E set(int index, E element) {
//判断索引下标 rangeCheck(index); //获取数组中index索引所在位置的数据元素 E oldValue = elementData(index);
//替换数组中index索引所在位置的数据元素内容 elementData[index] = element; return oldValue;//返回修改园所原始内容 }
get(int index)
获取方法
public E get(int index) {
//判断索引位置 rangeCheck(index); //返回索引位置数据 return elementData(index); }
toString()
转换方法,将集合中所有元素转换为字符串
public String toString() {
//获取迭代器 Iterator<E> it = iterator(); if (! it.hasNext()) return "[]"; //进行字符串组装 StringBuilder sb = new StringBuilder(); sb.append(‘[‘);
//无线循环 for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (! it.hasNext()) return sb.append(‘]‘).toString(); sb.append(‘,‘).append(‘ ‘); } }
Iterator<E> iterator()
获取迭代器
public Iterator<E> iterator() { return new Itr(); }
//迭代器
private class Itr implements Iterator<E> {
int cursor; // 当前位置
int lastRet = -1; // 记录- 1
int expectedModCount = modCount;//将集合实际修改次数复制给预期修改次数
Itr() {}
//判断集合是否有元素
public boolean hasNext() {
return cursor != size;
}
public E next() {
//检查预期修改次数和实际修改次数相等
checkForComodification();
//将光标复制给i变量
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) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
remove(Object 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; }
void clear()
清空方法
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
boolean contains(Object o)
判断集合中是否包含元素
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;
}
boolean isEmpty()
空实体判断
public boolean isEmpty() { return size == 0; }
1.ArrayList是如何扩容的?
第一次扩容10
以后每次扩容原有用量的1.5倍
2。数组新增海量数据,优化?
ArrayList底层,需要进行多次扩容,效率低下!
优化方案:使用构造,指定初始化容量
3.ArrayList插入或者删除元素一定比LinkedList慢?
不一定,因为LinkedList查找元素(node)很费时
ArrayList remove()
public E remove(int index) {
//索引校验 rangeCheck(index); //数组实际操作次数,多线程使用 modCount++;
//获取下标索引为index的元素 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; }
LinkedList remove()方法
public E remove(int index) {
//检查索引 checkElementIndex(index); return unlink(node(index)); }
//
E unlink(Node<E> x) {
//需要删除的元素
final E element = x.item;
//下一个元素
final Node<E> next = x.next;
//上一个元素
final Node<E> prev = x.prev;
if (prev == null) {//首节点
first = next;//把下一个节点置为首节点
} else {//非首节点
prev.next = next;//把当前节点置为下一个节点
x.prev = null;//把
}
if (next == null) {//尾节点
last = prev;//前一个节点置为尾节点
} else {
next.prev = prev;//
x.next = null;
}
//元素置为空
x.item = null;
//大小减1
size--;
//实际操作次数
modCount++;
return element;
}
//LinkedList 存储的第一个节点
transient Node<E> first;
//查找元素
Node<E> node(int index) {
// assert isElementIndex(index);
//判断索引是否小于数组大小的一般
if (index < (size >> 1)) {
//把第一个节点赋值给x
Node<E> x = first;
//从第一个节点开始往后读取,直到下标为index的元素
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//把最后一个节点赋值给x
Node<E> x = last;
//从最后一个节点开始,以次往前读取,直到下标为index的元素
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//node对象
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
4.ArrayList是线程安全的吗?如何解决线程共享?
不是线程安全的
解决方案:
1.添加同步代码块或者同步方法
2.使用vector替代ArrayList;不考虑线程安全的情况,更推荐ArrayList
3.通过工具类实现Collections.synchronizedList(new ArrayList<String>())创建数组
5.如何复制ArrayList到另一个ArrayList?
1.使用clone()
2.使用ArrayList构造
3.使用AddAll方法
4.以及循环遍历逐个添加
6.已知成员变量集合存储N多用户名称,在多线程环境下,使用迭代器读取集合数据同时保证还可以正常的写入数据到集合?
使用CopyOnWriteArrayList
7.ArrayList和LinkedList区别?
ArrayList
基于动态数组的结构
对于随机访问的get和set,ArrayList由于LinkedList
对于随机的add和remove,AraayList不一定比Linkedlistman(ArrayList底层由于是动态数组,因此并不是每次add和remove都需要创建新的数组)
LinedList
基于链表的数据结构
对于顺序操作,LinkedList不一定比ArrayList慢
对于随机操作,LikedList效率明显较低
自定义ArrAyList
1.定义成员变量
2.构造方法
3.定义添加、移除、修改、扩容方法
原文:https://www.cnblogs.com/ywzq/p/14315483.html