目录
4,序列化数组writeObject(java.io.ObjectOutputStream s)
5,反序列化数组readObject(java.io.ObjectInputStream s)
7,创建子数组subList(int fromIndex, int toIndex)
9,创建 ListIterator 迭代器listIterator(...)
10,foreach遍历 forEach(Consumer action)
1,删除元素
1.1,删除单个元素remove
remove(int index)
方法,移除指定位置的元素,并返回该位置的原元素。代码如下:
public E remove(int index) {
rangeCheck(index); // 校验 index 不要超过 size
modCount++; //增量++
E oldValue = elementData(index); //将index对应的元素赋值给 oldValue
int numMoved = size - index - 1; //计算集合需要移动元素个数
if (numMoved > 0) //如果需要移动元素个数大于0,就使用arrayCopy方法进行拷贝 注意:数据源和数据目的就是elementData
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work //将源集合最后一个元素置为null,尽早让垃圾回收机制对其进行回收
return oldValue; //返回被删除的元素
}
1.2, 移除多个元素removeRange
removeRange(int fromIndex, int toIndex)
方法批量移除 [fromIndex, toIndex)
的多个元素,注意不包括 toIndex
的元素噢。代码如下:
protected void removeRange(int fromIndex, int toIndex) {
modCount++; //增量++
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
测试(因为这个测试比较特殊Test02类继承了ArrayList)
@Test
public void test02(){
Test02 list = new Test02();
list.add("司理理");
list.add("苏小小");
list.add("李师师");
list.add("李师师1");
list.add("苏小小1");
list.add("司理理1");
list.removeRange(0,4);
System.out.println(list);
}
1.3,移除在 c
中的元素batchRemove
removeAll(Collection<?> c)
方法批量移除指定的多个元素。实现逻辑比较简单,但是看起来会比较绕当然看代码也会有点绕绕,嘿嘿。代码如下:
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c); //检验是否为空空指针
return batchRemove(c, false);
}
调用 batchRemove(Collection<?> c, boolean complement, final int from, final int end)
方法,批量移除指定的多个元素。代码如下
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try { // <1> 优化,顺序遍历 elementData 数组,找到第一个不符合 complement ,然后结束遍历。
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
complement
参数,翻译过来是“补足”的意思。怎么理解呢?表示如果 elementData
元素在 c
集合中时,是否保留。
- 如果
complement
为false
时,表示在集合中,就不保留,这显然符合#removeAll(Collection<?> c)
方法要移除的意图。 - 如果
complement
为true
时,表示在集合中,就暴露,这符合我们后面会看到的#retainAll(Collection<?> c)
方法要求交集的意图。
4,移除不在 c
中的元素retainAll
retainAll(Collection<?> c)
方法,求 elementData
数组和指定多个元素的交集。简单来说,恰好和 removeAll(Collection<?> c)
相反,移除不在 c
中的元素。代码如下:
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c); //判断传进来的集合是不是为空
return batchRemove(c, true);
}
也调用了 batchRemove(Collection<?> c, boolean complement, final int from, final int end)
方法,批量移除指定的多个元素
2,查找元素
2.1查找单个元素indexOf
indexOf(Object o)
方法,查找首个为指定元素的位置。代码如下:非常简单
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;
}
contains(Object o)
包含方法,就是基于该方法实现。代码如下:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
有时我们需要查找最后一个为指定元素的位置,所以会使用到lastIndexOf(Object o)
方法。代码如下:和上面对比就是循环一个从前面比对一个从后面比对
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
2.2,获取指定位置的元素get
get(int index)
方法,获得指定位置的元素。代码如下:
elementData(int index)
public E get(int index) {
rangeCheck(index); //校验下标是否超出
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
2.3,设置指定位置的元素set
set(int index, E element) 方法,设置指定位置的元素。代码如下:
public E set(int index, E element) {
rangeCheck(index); //校验是否下标越界
E oldValue = elementData(index); //.要修改的元素
elementData[index] = element; //将修改元素给要修改的位置
return oldValue; //将修改钱元素返回
}
2.4,转换成数组toArray()
toArray()
方法,将 ArrayList 转换成 []
数组。代码如下:
public Object[] toArray() {
//就是复制elementData数组,size是复制的长度
return Arrays.copyOf(elementData, size);
}
//CLASS类里的
public native Class<?> getComponentType();
Arrays.copyof
//这个方法就是取出传入数组的class对象作为第三个参数调用适用性更广的另一个函数而已.
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;
}
首先这个方法有两个泛型,一个是T,一个是U,T代表传入的第三个个参数newType(传入的类型的class对象),U 代表传入的第一个对象original(即原数组的数据类型)
三元运算符的判断条件**((Object)newType == (Object)Object[].class)是用来判断newType
是否是Object类型,在上述第一个方法的前提下代表判断原数组是否为Object类型的数组.
(Object)newType**这里为什么要转型是因为不转型会报错
如果判断为真,即原数组是Object类型数组,则直接创建一个给定长度newLength的新的Object数组即可.(为什么要创建新数组呢?因为这个函数目的就是复制一个数组的指定部分到一个新数组.)
如果判断为假,即原数组不是Object类型数组,则调用**(T[])
Array.newInstance(newType.getComponentType(), newLength)**这个方法是新建一个数组,数组类型为newType中元素的类型(默认返回Object类型,可强制转换为正确类型,详情看下列代码例),长度为 指定的newLength.
getComponentType()在class类里面本地方法,返回数组内的元素类型,不是数组时,返回null
public native Class<?> getComponentType();
System.arraycopy
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
2.5求哈希值hashCode()
hashCode()
方法,求 ArrayList 的哈希值。代码如下:
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
Object类理
public native int hashCode();
选择31的原因看看String的hashCode方法是怎样实现的
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
2.6, 判断2个list是否相等equals
equals(Object o)
方法,判断是否相等。代码如下:
public boolean equals(Object o) {
if (o == this) // 如果是自己,直接返回相等
return true;
if (!(o instanceof List)) // 如果不为 List 类型,直接不相等
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
可能第一眼让胖友比较费解的是,为什么根据类型是否为 ArrayList ,调用了两个不同的方法去比对呢?因为普通的 List ,我们只能使用 Iterator 进行迭代,相比 ArrayList 的 elementData
属性遍历,性能会略低一些。处处是细节哈
3,清空元素clear()
clear()
方法,清空数组。代码如下:
public void clear() {
modCount++; // 获得当前的数组修改次数
// clear to let GC do its work // 遍历数组,倒序设置为 null
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
4,序列化数组writeObject(java.io.ObjectOutputStream s)
writeObject(java.io.ObjectOutputStream s)
方法,实现 ArrayList 的序列化。代码如下:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff// 获得当前的数组修改次数
int expectedModCount = modCount;
// <1> 写入非静态属性、非 transient 属性
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
// 写入 size ,主要为了与 clone 方法的兼容
s.writeInt(size);
// Write out all elements in the proper order. 3> 逐个写入 elementData 数组的元素
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
// 如果 other 修改次数发生改变,则抛出 ConcurrentModificationException 异常
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
5,反序列化数组readObject(java.io.ObjectInputStream s)
readObject(java.io.ObjectInputStream s)
方法,反序列化数组。代码如下:
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff读取非静态属性、非 transient 属性
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored 读取 size ,不过忽略不用
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
int capacity = calculateCapacity(elementData, size);
SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.逐个读取
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
6,克隆clone()
clone()
方法,克隆 ArrayList 对象。代码如下:
public Object clone() {
try { // 调用父类,进行克隆
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size); // 拷贝一个新的数组
v.modCount = 0; // 设置数组修改次数为 0
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
7,创建子数组subList(int fromIndex, int toIndex)
subList(int fromIndex, int toIndex)
方法,创建 ArrayList 的子数组。代码如下:
SubList 不是一个只读数组,而是和根数组 root
共享相同的 elementData
数组,只是说限制了 [fromIndex, toIndex)
的范围
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
8, 创建 Iterator 迭代器iterator()
iterator()
方法,创建迭代器。一般情况下,我们使用迭代器遍历 ArrayList、LinkedList 等等 List 的实现类。代码如下:
创建 Itr 迭代器。Itr 实现 ListIterator 接口,是 ArrayList 的内部类虽然说 AbstractList 也提供了一个 Itr 的实现,但是 ArrayList 为了更好的性能,所以自己实现了,在其类上也有注释“An optimized version of AbstractList.Itr”。
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
index of next element to return下一个访问元素的位置,从下标 0 开始。
int cursor;
// index of last element returned; -1 if no such上一次访问元素的位置。 初始化为 -1 ,表示
//无上一个访问的元素 遍历到下一个元素时,lastRet 会指向当前元素,而 cursor 会指向下一个元
// 素。这样,如果我们要实现 remove 方法,移除当前元素,就可以实现了。 移除元素时,设置为 -1
//,表示最后访问的元素不存在了,都被移除咧。
int lastRet = -1;
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 对 Iterator 的 4 个实现方法。
hasNext()
方法,判断是否还可以继续迭代。代码如下
public boolean hasNext() {
//cursor 如果等于 size ,说明已经到数组末尾,无法继续迭代了。
return cursor != SubList.this.size;
}
next()
方法,下一个元素。代码如下
public E next() {
// 校验是否数组发生了变化
checkForComodification();
//i 记录当前 cursor 的位置
int i = cursor;
// 判断如果超过 size 范围,抛出 NoSuchElementException 异常
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
//判断如果超过 elementData 大小,说明可能被修改了,抛出 ConcurrentModificationException 异常
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
//cursor 指向下一个位置
cursor = i + 1;
//返回当前位置的元素
return (E) elementData[offset + (lastRet = i)];
}
remove()
方法,移除当前元素。代码如下:
public void remove() {
// 如果 lastRet 小于 0 ,说明没有指向任何元素,抛出 IllegalStateException 异常
if (lastRet < 0)
throw new IllegalStateException();
// 校验是否数组发生了变化
checkForComodification();
//移除 lastRet 位置的元素
try {
SubList.this.remove(lastRet);
//cursor 指向 lastRet 位置,因为被移了,所以需要后退下
cursor = lastRet;
//lastRet 标记为 -1 ,因为当前元素被移除了
lastRet = -1;
//记录新的数组的修改次数
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
forEachRemaining(Consumer<? super E> action)
方法,消费剩余未迭代的元素。代码如下
public void forEachRemaining(Consumer<? super E> action) {
int i, hi, mc; // hoist accesses and checks from loop
ArrayList<E> lst; Object[] a;
if (action == null)
throw new NullPointerException();
if ((lst = list) != null && (a = lst.elementData) != null) {
if ((hi = fence) < 0) {
mc = lst.modCount;
hi = lst.size;
}
else
mc = expectedModCount;
if ((i = index) >= 0 && (index = hi) <= a.length) {
for (; i < hi; ++i) {
@SuppressWarnings("unchecked") E e = (E) a[i];
action.accept(e);
}
if (lst.modCount == mc)
return;
}
}
throw new ConcurrentModificationException();
}
9,创建 ListIterator 迭代器listIterator(...)
listIterator(...)
方法,创建 ListIterator 迭代器。代码如下:
//这个方法可以选择多少个元素去迭代
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
//没有参数的
public ListIterator<E> listIterator() {
return new ListItr(0);
}
创建 ListItr 迭代器。ListItr 实现 了ListIterator 接口,是 ArrayList 的内部类。虽然说 AbstractList 也提供了一个 ListItr 的实现,但是为了ArrayList的 性能,所以自己实现了,在其类上也有注释“An optimized version of AbstractList.ListItr”。
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();
}
}
}
10,foreach遍历 forEach(Consumer<? super E> action)
forEach(Consumer<? super E> action)循环遍历代码如下:
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();
}
}