我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码
文章目录
- 一、架构
- 二、 RandomAccess 接口子类
- 三、 AbstractSequentialList 抽象类子类
- 四、ArrayList 类
- 4.1 变量
- 4.2 方法
- 4.2.1 初始化(3个)
- 3.2.2 get 与 set 方法
- 4.2.3 add 方法
- 4.2.4 ensureCapacityInternal 方法
- 4.2.5 calculateCapacity 方法
- 4.2.6 ensureExplicitCapacity 方法
- 4.2.7 grow 方法
- 4.2.8 remove 方法
- 4.2.9 removeAll 方法
- 4.2.10 batchRemove 方法(private)
- 4.2.11 retainAll 方法
- 4.2.12 trimToSize 方法
- 4.2.13 fastRemove 方法 (private)
- 4.2.14 clear 方法
- 4.2.15 subList 方法
- 4.2.16 writeObject 方法
- 4.2.17 readObject 方法
- 4.2.18 为什么elementData是transient的?
- 4.3 是否指定 capacity 带来的区别
- 五、Vector 类
- 六、CopyOnWriteArrayList 类
- 七、ImmutableList 类
- 八、LinkedList 类
- 九、番外篇
一、架构
1.1 常见子类 UML
1.2 简述
二、 RandomAccess 接口子类
2.1 ArrayList 类
2.2 Vector 类
2.3 CopyOnWriteArrayList 类
2.4 ImmutableList 类
三、 AbstractSequentialList 抽象类子类
3.1 LinkedList 类
四、ArrayList 类
- java.util.ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 注意:实现了 RandomAccess,表明是支持随机访问,那么也就是内部是数组Array 结构。
4.1 变量
变量名 | 备注 |
---|---|
private static final int DEFAULT_CAPACITY = 10 | 内部Array数组默认长度,不够再扩容。 |
private static final Object[] EMPTY_ELEMENTDATA = {} | 空数组。(标志性的)构造方法、trimToSize 、readObject用到 |
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; | 确定容量用的。我们将此与EMPTY_ELEMENTDATA区分开来,以了解在添加第一个元素时要膨胀多少。ensureCapacity、calculateCapacity 用到 |
transient Object[] elementData | 元素数组 |
private int size | 数组长度 |
4.2 方法
4.2.1 初始化(3个)
- 默认构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 带initialCapacity构造方法
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);
}
}
- 带 Collection 的构造方法
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;
}
}
- 三构造方法,注意一下 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 与 EMPTY_ELEMENTDATA 的区别,前面那个是默认的。
3.2.2 get 与 set 方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
都是先检查下标是否溢出,然后再进行 get 或者 set。
4.2.3 add 方法
- java.util.ArrayList#add(E)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
- 先检查数组内部容量 ensureCapacityInternal
- 设置元素
4.2.4 ensureCapacityInternal 方法
- java.util.ArrayList#ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
- calculateCapacity 先计算所需要数组容量
- ensureExplicitCapacity 确保容量充足,必要时候扩容
- 上层调用:
=== 点击查看top目录 ===
4.2.5 calculateCapacity 方法
- java.util.ArrayList#calculateCapacity (计算所需要数组容量 )
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 若是默认的,也即是调用了
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
- ArrayList默认构造方法下,会进行扩容到合适的容量。
- 返回最少需要的容量
- 上层调用:
- ensureCapacityInternal 确保合适容量
- readObject 从输入流转换成 List 会用到
4.2.6 ensureExplicitCapacity 方法
- java.util.ArrayList#ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
- modCount++ ,那么加入你在Iterator遍历,那么你就会抛出 ConcurrentModificationException
- 判断是否能够装下新元素,不够的话就 grow
4.2.7 grow 方法
- java.util.ArrayList#grow
- 容量增长方法,内部是调用 native 方法进行复制。
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);
}
- 此处应该注意,如果每次添加一个元素都要进行扩容的话,那么及其浪费性能。
4.2.8 remove 方法
方法名 | 备注 |
---|---|
public E remove(int index) | 按 index 删除 |
public boolean remove(Object o) | 按 Object 删除 |
public boolean removeIf(Predicate<? super E> filter) | 按条件删除 |
protected void removeRange(int fromIndex, int toIndex) | 删除一定范围内的元素 |
public boolean removeAll(Collection<?> c) | 批量删除 |
- java.util.ArrayList#remove(int) 删除 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;
}
内部原理:
- 拿到老的 Element ,待会返回
- 使用 native 底层的复制方法,把 index+1 以及后面的元素全部复制到index的位置来。
- 最后一个元素设置为null
- size - 1
- java.util.ArrayList#remove(java.lang.Object) 删除某个元素
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;
}
内部原理:
- 拿到老的 Element
- 使用 native 底层的复制方法,把 index+1 以及后面的元素全部复制到index的位置来。fastRemove方法
- 最后一个元素设置为null
- size - 1
- return true / false
- 注意一下:若有100w个数据,你从头删到尾巴,那么肯定非常耗时。因为每次都要进行复制。
4.2.9 removeAll 方法
- java.util.ArrayList#removeAll
- 把Collection中包含c集合中的元素都移除掉(求差集)
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
4.2.10 batchRemove 方法(private)
- java.util.ArrayList#batchRemove
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
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.
// r != size 的情况: c.contains() 丢出 Exception,(看下 java.util.AbstractCollection#contains )
if (r != size) {
// 如果丢出异常,那么把后面没处理的都给衔接上放在原 elementData 上面
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
// retainAll 情况下:如果 w == size ,那么说明原来的Collection 与要处理的 Collection 一模一样
// removeAll 情况下:如果 w == size ,那么一个没删除
// 那么 w!= size 是什么情况呢?就是上面for处理后,w 后面还有元素,后面的元素都不要了,需要设置为 null,协助 gc
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;
}
- 看下上层引用
- retainAll 与 removeAll
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
---
retainAll:
elementData : A B C D F G
c : A C E
size = 10
elementData : A C
---
removeAll:
elementData : A B C D F G
c : A C E
size = 10
elementData : B D F G
4.2.11 retainAll 方法
- java.util.ArrayList#retainAll 方法
- 把Collection中不是c的元素移除掉(求合集)
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
4.2.12 trimToSize 方法
- java.util.ArrayList#trimToSize 方法
- 压缩容量,假如内存1w的数组里面只有1000个元素,调用这个方法就是把这1000个元素copy到另外一个新的数组,指针指向这个新的数组。
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
4.2.13 fastRemove 方法 (private)
- java.util.ArrayList#fastRemove 方法
private void fastRemove(int index) {
modCount++;
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
}
4.2.14 clear 方法
- java.util.ArrayList#clear 方法
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
- 数组内元素指针全部指向null,协助GC
- size 设置为 0
- 思考下,为什么不直接 elementData = null
我自己的看法:如果你不想用这个list了,那么直接 list = null,如果你还想用,那么就调用 clear,免得你待会还得再 new 一个。
4.2.15 subList 方法
- java.util.ArrayList#subList 方法
- 浅复制,得到子List,实际上操作的还是父本身的list内部元素,详情看内部类 subList 实现
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 + ")");
}
4.2.16 writeObject 方法
- java.util.ArrayList#writeObject 方法
- 将 Collection 写入输出流 ObjectOutputStream
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
4.2.17 readObject 方法
- java.util.ArrayList#readObject 方法
- 将输入流 ObjectInputStream 写入Collection
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
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();
}
}
}
4.2.18 为什么elementData是transient的?
- ArrayList在序列化的时候会调用writeObject,直接将size和element写入ObjectOutputStream;反序列化时调用readObject,从ObjectInputStream获取size和element,再恢复到elementData。
- 为什么不直接用elementData来序列化,而采用上诉的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。
4.2.19 toArray 方法
- java.util.ArrayList#toArray() 方法
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
- java.util.Arrays#copyOf(T[], int) 方法
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
- java.util.Arrays#copyOf(U[], int, java.lang.Class<? extends T[]>) 方法
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;
}
- java.lang.System#arraycopy
- 底层是深复制
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
- List内部也是数组Array,复制的底层就是调用 System#arraycopy 将List内部数组复制成一个新的Object数组
=== 点击查看top目录 ===
4.2.20 size 方法
- java.util.ArrayList#size 方法
public int size() {
return size;
}
4.3 是否指定 capacity 带来的区别
private static void test01() {
ArrayList<String> stringList = new ArrayList<>(100000000); // 162ms
ArrayList<String> stringList = new ArrayList<>(1); // 9000ms
long begin = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
stringList.add("A");
}
long end = System.currentTimeMillis();
System.out.println("ArrayList -> " + (end - begin));
}
- 162ms VS 9000m ,原因就是内部的 copy 操作,每次扩容都会全量复制一次。
五、Vector 类
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 在 ArrayList 基础上,所有方法加上 synchronized 。
六、CopyOnWriteArrayList 类
- 实现 RandomAccess 的常用子类
- 该类,写的时候加锁,然后全copy,用于写少读多的场合。读的时候不加锁。
6.1 变量
变量 | 备注 |
---|---|
final transient ReentrantLock lock = new ReentrantLock(); | 写的时候加锁 |
private transient volatile Object[] array; | 数组,存放元素,transient说明重写了 readObject 与 writeObject 方法,目的是为了不存储空数据 |
6.2 代码
- 整体代码:
package java.util.concurrent;
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
...
}
- 查询方法相比 ArrayList 无任何改动。
- 写入方法:
6.2.1 set 方法
- java.util.concurrent.CopyOnWriteArrayList#set 方法
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
- 注意
- 写的时候,先上 lock
- Arrays.copyOf 内部使用 native 方法进行复制
- 替换掉老数组
- 释放 lock
七、ImmutableList 类
- 该类内的全部元素,一初始化便注定不能改变。
- 元素不可改变的方法,任何一个写操作都会抛出 UnsupportedOperationException .
- 抛出异常的方法
方法 | 描述 |
---|---|
add(E e) | throw new UnsupportedOperationException() |
remove(Object object) | throw new UnsupportedOperationException(); |
addAll(Collection<? extends E> newElements) | throw new UnsupportedOperationException(); |
removeAll(Collection<?> oldElements) | throw new UnsupportedOperationException(); |
retainAll(Collection<?> elementsToKeep) | throw new UnsupportedOperationException(); |
clear() | throw new UnsupportedOperationException(); |
package com.google.common.collect;
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial") // we're overriding default serialization
public abstract class ImmutableList<E> extends ImmutableCollection<E>
implements List<E>, RandomAccess {
}
7.1 构造方法 ImmutableList
ImmutableList() {}
- default 类型的构造方法,说明只供同一个 package 下的使用,真正的初始化方法是 of
7.2 初始化方法 of
@SuppressWarnings("unchecked")
public static <E> ImmutableList<E> of() { return (ImmutableList<E>) EMPTY; }
public static <E> ImmutableList<E> of(E element) { return new SingletonImmutableList<E>(element); }
public static <E> ImmutableList<E> of(E e1, E e2) { return construct(e1, e2); }
public static <E> ImmutableList<E> of(E e1, E e2, E e3) { return construct(e1, e2, e3); }
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) { return construct(e1, e2, e3, e4); }
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) { return construct(e1, e2, e3, e4, e5);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {return construct(e1, e2, e3, e4, e5, e6);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {return construct(e1, e2, e3, e4, e5, e6, e7);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { return construct(e1, e2, e3, e4, e5, e6, e7, e8);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);}
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) {return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11);}
public static <E> ImmutableList<E> of( E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12, E... others) {
Object[] array = new Object[12 + others.length];
array[0] = e1;
array[1] = e2;
array[2] = e3;
array[3] = e4;
array[4] = e5;
array[5] = e6;
array[6] = e7;
array[7] = e8;
array[8] = e9;
array[9] = e10;
array[10] = e11;
array[11] = e12;
System.arraycopy(others, 0, array, 12, others.length);
return construct(array);
}
- 我还是没搞懂为什么要写那么多个 of 方法,直接下面这样不行吗???
public static <E> ImmutableList<E> of( E e1,E... others) {
Object[] array = new Object[1 + others.length];
array[0] = e1;
System.arraycopy(others, 0, array, 1, others.length);
return construct(array);
}
7.3 construct 方法
private static <E> ImmutableList<E> construct(Object... elements) {
return asImmutableList(checkElementsNotNull(elements));
}
- private 与 static 表明是一个静态私有构造方法,也就是该方法不会被外部调用。
7.4 checkElementsNotNull 方法
- 该方法确保存入的元素 Element 不能为 null
- ArrayList 、LinkedList 、Vector 允许null元素
static Object[] checkElementsNotNull(Object... array) {
return checkElementsNotNull(array, array.length);
}
static Object[] checkElementsNotNull(Object[] array, int length) {
for (int i = 0; i < length; i++) {
checkElementNotNull(array[i], i);
}
return array;
}
// We do this instead of Preconditions.checkNotNull to save boxing and array
// creation cost.
static Object checkElementNotNull(Object element, int index) {
if (element == null) {
throw new NullPointerException("at index " + index);
}
return element;
}
- 虽然不能写,但是也就不能完全实现线程安全,毕竟 sort 方法还不是安全的。
八、LinkedList 类
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
- 注意:这个类就不实现 RandomAccess 随机存储结构,而是
8.1 变量
变量名 | 备注 |
---|---|
transient Node last; | 元素数组 |
transient Node first; | 元素数组 |
transient int size = 0 | 数组长度 |
- 注意:变量都是 transient
8.2 方法 (public)
8.2.1 插入 add
方法名 | 备注 |
---|---|
public boolean add(E e) | 往最后面插入 |
public void add(int index, E element) | 在某个 index 后插入 element |
public void addFirst(E e) | 往最前面插入 |
public void addLast(E e) | 往最后面插入 |
public boolean addAll(Collection<? extends E> c) | 插入某个Collection |
public boolean addAll(int index, Collection<? extends E> c) | 在固定 index 后面插入某个Collection |
public boolean offer(E e) | 往最后面插入 |
public boolean offerFirst(E e) | 往最前面插入 |
public boolean offerLast(E e) | 往最后面插入 |
public void push(E e) | 往最前面插入addFirst(e); |
- add = offer 插最后 ,push 插开头
8.2.2 删除 remove
方法名 | 备注 |
---|---|
public E removeFirst() | 摘掉第一个 |
public E removeLast() | 摘掉最后一个 |
public E remove(int index) | 移除掉某个 index 下的element |
public boolean remove(Object o) | 移除掉某个元素 |
public E remove() | 拉出第一个元素(要remove,遇 null 抛Exception) |
public boolean removeFirstOccurrence(Object o) | remove(o); |
public boolean removeLastOccurrence(Object o) | 从后往前面删 |
public E poll() | 拉出第一个元素(要remove,遇 null 返回 null) |
public E pollFirst() | 拉出第一个元素(要remove,遇 null 返回 null) |
public E pollLast() | 拉出最后一个元素(要remove,遇 null 返回 null) |
public E pop() | pop出第一个元素(要remove,遇 null 抛Exception) removeFirst(); |
- remove = pop 遇 null 抛出 Exception
- poll 遇 null 返回 null
8.2.3 设置 set
方法名 | 备注 |
---|---|
public E set(int index, E element) | 设置 index 下面的 Element |
8.2.4 get 查询
方法名 | 备注 |
---|---|
public E get(int index) | 获取某个 index 下的 Element |
public E getFirst() | 拿到第一个Element |
public E getLast() | 拿到最后一个 Element |
public E element() | 拿到第一个元素 (不remove,遇 null 抛Exception) |
public E peek() | 拿到第一个元素(不remove,遇 null 返回 null) |
public E peekFirst() | 拿到第一个元素(不remove,遇 null 返回 null) |
public E peekLast() | 拿到最后一个元素(不remove,遇 null 返回 null) |
8.2.5 其他操作
方法名 | 备注 |
---|---|
public int indexOf(Object o) | 查找某个元素存在的下标,找不到返回 -1 |
public int lastIndexOf(Object o) | 查找某个元素存在的下标(从后面开始找),找不到返回 -1 |
public boolean contains(Object o) | 是否包含某个 Element |
public int size() | collection 长度 |
public void clear() | 清除元素 |
public ListIterator listIterator(int index) | 拿到 ListItr |
public Iterator descendingIterator() | 拿到从后往前的 Iterator |
public Object clone() | 克隆,浅复制 shallow copy |
public Object[] toArray() | 转成数组 |
public Spliterator spliterator() | 拿到从前往后的 Iterator |