标签:swa 方式 math test class rom 效率 shift str
底层是一个Object[]数组来维护数据
/**
* Appends the specified element to the end of this list.
* 追加一个具体的元素到list的末尾
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal的代码如下:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
calculateCapacity的代码如下:
这里第一次调用add方法的时候,elementData为空数组,进入if条件,所以calculateCapacity方法返回DEFAULT_CAPACITY变量的值为10,返回给ensureExplicitCapacity方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
ensureExplicitCapacity方法如下:
该方法是确保精确的容量,传入的参数为10,如果大于数组长度,即容量不够,会调用grow方法扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
grow方法如下:
这里oldCapacity为0,newCapacity也是0,进入第一个if,则newCapacity为10,然后调用Arrays.copyOf方法拷贝数组
第二个if判断newCapacity如果超过Integer.MAX_VALUE - 8,调用hugeCapacity方法判断,如果大于MAX_ARRAY_SIZE,取Integer.MAX_VALUE,否则取MAX_ARRAY_SIZE
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
Arrays.copyOf方法如下:
这里传入的original为Object[],newLength为10,在重载方法中,newType为Object[].class,所以copy为(T[]) new Object[newLength],然后执行System.arraycopy方法进行数组拷贝,即从original数组0位置开始移动0个元素到copy数组,相当于什么都没拷贝,直接返回了新创建的数组T[] copy,所以最终elementData返回了长度为10的数组,意味着确保容量操作已经完成,然后通过elementData[size++] = e完成元素的添加
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
所以可以看出,当添加元素的时候,如果数组大小不够,会进入grow方法,该方法会对数组进行1.5倍扩容,如果不指定ArrayList大小,就会频繁扩容和拷贝,影响性能
该方法是在指定位置插入一个元素,代码如下:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
首先通过rangeCheckForAdd方法检查index是否超标:
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
然后通过ensureCapacityInternal确保容量,之后调用System.arraycopy方法将index之后长度为size - index的元素移动到index+1位置,最后将element元素插入index位置,将size+1
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
首先是rangeCheck方法,检查index是否超出范围:
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
然后是elementData(int index)方法,通过数组下标获取元素
E elementData(int index) {
return (E) elementData[index];
}
最后将index位置的元素用element替换,返回原来的元素
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
首先检查index范围,然后直接通过数组下标返回元素
public E remove(int index) {
rangeCheck(index);
modCount++;
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;
}
首先校验index是否合法,然后获取替换前的元素,然后计算需要拷贝的元素个数,如果大于0,进行拷贝,最后将数组最后一个元素赋值为null,让GC回收
首先判断filter不为null,然后通过BitSet和for循环找到符合条件的元素,将index放入BitSet中,增加removeCount,如果removeCount大于0,通过for循环进行元素交换,然后把newSize之后的元素置为null,最后返回是否成功
public boolean removeIf(Predicate<? super E> filter) {
//判断filter不为null
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
final int size = this.size;
for (int i = 0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked") final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i = 0, j = 0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k = newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
this.size = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
在该过程中使用了modCount和expectedModCount做判断,这两个值表示的是如果执行该方法,开始删除符合条件的元素时,不能有另外的线程修改当前的ArrayList,如果这时候有别的线程修改,那么modCount会发生变化,当发现modCount和执行方法开始时expectedModCount不一致的话,就会抛出ConcurrentModificationException,即并发修改异常,删除失败,这就是fail-fast机制,可以让当前线程快速失败,不会产生资源竞争,同时也导致了ArrayList线程不安全,不能并发操作
方法1通过for循环遍历,通过get方法访问元素
方法2和方法3都是通过迭代器遍历
方法4也是通过for循环和数组的下标来遍历
方法5时通过stream的API操作,效率不如方法4
public class ArrayListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
// System.out.println(list.set(1,"ddd"));
// System.out.println(list.get(1));
//遍历方法1
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//方法2
for (String s : list) {
System.out.println(s);
}
//方法3
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
//方法4
list.forEach(data -> System.out.println(data));
//方法5
list.stream().forEach(data -> System.out.println(data));
}
}
核心就是for循环,通过数组操作获取对应元素,传递Consumer函数表达式,执行相应逻辑
public void forEach(Consumer<? super E> 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();
}
}
public Iterator<E> iterator() {
return new Itr();
}
直接返回一个new Itr()对象,这个内部类是一个迭代器,如下:
这里hasNext方法里面判断cursor的值和数组大小是否相等,如果不相等就返回true,然后next方法里面,checkForComodification方法做并发访问检查,之后用i保存cursor值,然后做校验,之后获取ArrayList的elementData数组,再次做并发访问检查,然后将cursor+1,将i的值赋给lastRet,并且返回数组中的该元素
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;
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();
}
}
@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();
}
}
该类继承了Itr类,实现了向前遍历的功能
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
@SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
ArrayList有两个迭代器Itr和ListItr,前者可以向后迭代,后者既可以向前又可以向后迭代
这两个迭代器不是并发安全的
遍历List的方法主要是通过for循环+数组下标和指针移动两种方式
第一个方法底层使用Arrays.copyOf拷贝到数组
第二个方法需要传递一个目标数组,如果目标数组比ArrayList小,通过Arrays.copyOf扩容成和ArrayList大小一样的数组,如果目标数组比ArrayList大,直接使用System.arraycopy拷贝所有元素,并且将后面的元素置为null
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a‘s runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
首先检查范围,然后创建一个SubList内部对象,然后在构造函数传入了this,即ArrayList创建的对象本身,将其赋给parent,其他方法也是基于原数组的数据进行操作,根据fromIndex和toIndex限定了访问范围
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
public E set(int index, E e) {
rangeCheck(index);
checkForComodification();
E oldValue = ArrayList.this.elementData(offset + index);
ArrayList.this.elementData[offset + index] = e;
return oldValue;
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
}
public int size() {
checkForComodification();
return this.size;
}
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
...
}
标签:swa 方式 math test class rom 效率 shift str
原文地址:https://www.cnblogs.com/jordan95225/p/13580453.html