package java.util;
import java.util.function.Consumer;
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/**
* LinkedList实现双链表接口。实现所有可选集合操作,并允许所有操作
* 元素(包括{@code null})所有的操作都按照双链的预期执行集合。
* 索引到集合中的操作将遍历集合开始或结束,以较接近指定索引的为准。
* 注意,这个实现不是同步的如果多个线程同时访问一个链表,并且至少
* 其中一个线程从结构上修改集合,它必须在
* 外部进行同步。结构修改是包括添加或删除一个或多个元素;仅设置值
* 元素不是结构修改。这通常是通过自然地同步某些对象来完成封装集合。
* Java集合框架
*
* @param the type of elements held in this collection
* @author Josh Bloch
* @see List
* @see ArrayList
* @since 1.2
*/
class LinkedList
extends AbstractSequentialList
implements List, Deque, Cloneable, java.io.Serializable {
//用来记录元素数量
transient int size = 0;
/***
* 在源码中,这个内部类是在代码的后面些,提到前面进行说明。
* Node节点就是LinkedList链表中的节点元素了,该类包含
* 一个前驱节点引用、一个后继节点引用和节点值,值类型是一个泛型,
* 只有一个有参构造方法
*/
private static class Node {
E item;
Node next;
Node prev;
Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
/**
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
* 指向第一个节点的指针。
*/
transient Node first;
/**
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
* 指向最后一个节点的指针。
*/
transient Node last;
/**
* 无参构造方法
*/
public LinkedList() {
}
/**
* 按照集合的c中元素的顺序构造一个LinkedList
*/
public LinkedList(Collection extends E> c) {
this();
addAll(c);
}
/**
* 生成一个Node节点,将其作为头节点插入集合,
* 然后将参数e的值设置为节点的值
*/
private void linkFirst(E e) {
final Node f = first;
final Node newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
// 链表结构发生改变,modCount++
modCount++;
}
/**
* 生成一个Node节点,将其作为尾节点插入集合,
* 然后将参数e的值设置为节点的值
*/
void linkLast(E e) {
final Node l = last;
final Node newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
// 链表结构发生改变,modCount++
modCount++;
}
/**
* 在非null节点succ之前插入元素e
*/
void linkBefore(E e, Node succ) {
// assert succ != null;
// 源码并没有判断succ为空,如果传入空succ
//,则会报错抛出NULLPOINTEXCEPT
final Node pred = succ.prev;
final Node newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
// 链表结构发生改变,modCount++
modCount++;
}
/**
* 取消链接非空的第一个节点f。
*/
private E unlinkFirst(Node f) {
// assert f == first && f != null;
final E element = f.item;
final Node next = f.next;
f.item = null;
f.next = null; // 让GC可以收集被断开的对象
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
/**
* 取消链接非空的最后一个节点l
*/
private E unlinkLast(Node l) {
// assert l == last && l != null;
final E element = l.item;
final Node prev = l.prev;
l.item = null;
l.prev = null; // 让GC可以收集被断开的对象
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
/**
* 取消链接非空节点x
*/
E unlink(Node x) {
// assert x != null;
final E element = x.item;
final Node next = x.next;
final Node 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;
size--;
modCount++;
return element;
}
/**
* 返回此集合中的第一个元素
*/
public E getFirst() {
final Node f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
/**
* 返回此集合中的最后一个元素
*/
public E getLast() {
final Node l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
/**
* 从此集合中删除并返回第一个元素。
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() {
final Node f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* 从此集合中删除并返回最后一个元素
*
* @return the last element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeLast() {
final Node l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
/**
* 在此集合的开头插入指定的元素.
*
* @param e the element to add
*/
public void addFirst(E e) {
linkFirst(e);
}
/**
* 将指定的元素追加到此集合的末尾.
* 本方法相当于add
*/
public void addLast(E e) {
linkLast(e);
}
/**
* 如果此集合包含指定的元素,则返回{@code true}。
* 更正式的是,当且仅当此集合至少包含一个元素{@code e},当
* (o==null?e==null:o.equals(e))时,才返回{@code true}
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}
/**
* 返回此集合中的元素数。
*/
public int size() {
return size;
}
/**
* 将指定的元素追加到此集合的末尾。
*/
public boolean add(E e) {
// add方法就是调用了linkLast方法,将元素添加的最后
linkLast(e);
return true;
}
/**
* 从此集合中删除第一次出现的指定元素,
* 如果它存在。如果此集合不包含该元素,则为
* 不变。
*/
public boolean remove(Object o) {
if (o == null) {
for (Node x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
// 上面的那些代码可能会让人觉得,写的不够简洁,可以写的像如下:
// for (Node x = first; x != null; x = x.next) {
// if (Objects.equals(o, x.item)) {
// unlink(x);
// return true;
// }
// }
// 如果您有此疑问的话,说明您的逻辑能力很厉害,但是缺乏实际的考虑,
// 代码的简洁不代表效率高,就如上面的代码时间复杂度是O(n)级别的,
// Objects.equals(o, x.item)看似很简洁但是内部判断
// (a == b) || (a != null && a.equals(b))
// 复杂,在复杂度为O(n)的循环里,每一个语句都将可能执行n次,
// 作为一次就可判断的,我们就要考虑像源码写的那样了
return false;
}
/**
* 将指定集合中的所有元素追加到末尾此集合,详细信息等到讲解addAll(size, c)时再说明
*/
public boolean addAll(Collection extends E> c) {
return addAll(size, c);
}
/**
* 将指定集合中的所有元素插入到此中
* 集合, 同时在指定的位置开始. 移动元素
* 目前在该位置(如果有)以及任何后续元素
*/
public boolean addAll(int index, Collection extends E> c) {
// 检查index是否满足:index >= 0 && index <= size;
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
// 如果添加进来的集合为空,则直接返回false结束本方法
if (numNew == 0)
return false;
// 初始化前驱和后继节点引用对象
Node pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
// node方法通过循环获取并返回第index个位置的元素
succ = node(index);
pred = succ.prev;
}
// 通过增强for循环,将a中的所以元素添加进集合中
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
// size加上插入的元素
size += numNew;
modCount++;
return true;
}
/**
* 从此集合中删除所有元素。
* 此调用返回后集合将被清空。
*/
public void clear() {
// 清除节点之间的所有链接是“不必要的”,
// 使用for循环将所有引用变量赋值为null,
// 主要是为了帮助GC优化,防止内存泄漏
for (Node x = first; x != null; ) {
Node next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
// 位置访问操作
/**
* 返回此集合中指定位置的元素。
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
/**
* 用element替换此集合中指定位置的节点上的值
*/
public E set(int index, E element) {
checkElementIndex(index);
Node x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
/**
* 将指定元素插入此集合中的指定位置。
* 移动当前在该位置的元素(如果有的话)和任何
* 右边的后续元素(在其索引中添加一个)。
*/
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
// 将元素加到最后面
linkLast(element);
else
// 插入到指定位置
linkBefore(element, node(index));
}
/**
* 删除此集合中指定位置的元素。转移任何
* 左边的后续元素(从索引中减去一个)。
* 返回从集合中删除的元素。
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
/**
* 判断参数是否是现有元素的索引。
*/
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
/**
* 判断参数是否是有效位置的索引
* 迭代器或添加操作。
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
/**
* 构造一个IndexOutOfBoundsException详细消息。
* 在错误处理代码的许多可能的重构中,
* 这种“概述”在服务器和客户端虚拟机上表现最佳。
*/
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* Returns指定元素索引处的(非null)节点。
*/
Node node(int index) {
// assert isElementIndex(index);
// 为加快查找速度,先判断index是在偏前面还是偏后面,
// 然后在循环查找,时间复杂度从O(n)变成O(n/2)
if (index < (size >> 1)) {
Node x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
// 搜索操作
/**
* 返回指定元素第一次出现的索引
* 在此集合中,如果此集合不包含该元素,则返回-1。
* 更正式地,返回最低索引{@code i}
* 如果有(o == null ? get(i)== null: o.equals(get(i)))则返回i
* 没有这样的索引返回-1。
*/
public int indexOf(Object o) {
int index = 0;
// 这里与remove类似
if (o == null) {
for (Node x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
/**
* 返回指定元素最后一次出现的索引
* 在此集合中,如果此集合不包含该元素,则返回-1。
* 更正式地,返回最高指数{@code i}
* 如果有(o == null ? get(i)== null: o.equals(get(i)))则返回i
* 或-1如果没有这样的索引。
*/
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
// 队列操作。
/**
* 检索但不删除此集合的头部(第一个元素)。
*
* 返回头节点的值
*/
public E peek() {
final Node f = first;
return (f == null) ? null : f.item;
}
/**
* 检索但不删除此集合的头部(第一个元素)。
*
* 和peek()的区别是,该方法如果first为null,则会抛出异常
*/
public E element() {
return getFirst();
}
/**
* 检索并删除此集合的头部(第一个元素)。poll轮询
*/
public E poll() {
final Node f = first;
return (f == null) ? null : unlinkFirst(f);
}
/**
* 检索并删除此集合的头部(第一个元素)。
*/
public E remove() {
return removeFirst();
}
/**
* 将指定的元素添加为此集合的尾部(最后一个元素)。
*/
public boolean offer(E e) {
return add(e);
}
// Deque operations
/**
* 在指定集合的前面插入指定的元素。
*/
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
/**
* 在此集合的末尾插入指定的元素。
*/
public boolean offerLast(E e) {
addLast(e);
return true;
}
/**
* 检索但不删除此集合的第一个元素,
* 如果此集合为空,则返回{@code null}。
*
* 与peek()一样
*/
public E peekFirst() {
final Node f = first;
return (f == null) ? null : f.item;
}
/**
* 检索但不删除此集合的最后一个元素,
* 如果此集合为空,则返回{@code null}。
*/
public E peekLast() {
final Node l = last;
return (l == null) ? null : l.item;
}
/**
* 检索并删除此集合的第一个元素,
* 如果此集合为空,则返回{@code null}。
*/
public E pollFirst() {
final Node f = first;
return (f == null) ? null : unlinkFirst(f);
}
/**
* 检索并删除此集合的最后一个元素,
* 如果此集合为空,则返回{@code null}。
*/
public E pollLast() {
final Node l = last;
return (l == null) ? null : unlinkLast(l);
}
/**
* 将元素推送到此集合所表示的堆栈上。其他
* 单词,在此集合的前面插入元素。
*/
public void push(E e) {
addFirst(e);
}
/**
* 弹出此集合所代表的堆栈中的元素。其他
* words,删除并返回此集合的第一个元素。
*
* 此方法相当于{@link #removeFirst()}。
*/
public E pop() {
return removeFirst();
}
/**
* 删除此中第一次出现的指定元素
* list(从头到尾遍历集合时)。如果是集合不包含
* 该元素,则不变。
*/
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
/**
* 删除此中最后一次出现的指定元素
* list(从头到尾遍历集合时)。如果是集合不包含
* 该元素,则不变。
*/
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
// int index = lastIndexOf(o);
// if(index != -1){
// unlink(node(index));
// return true;
// }
// 上面的代码,不写成这样简洁的方式,也是同理,
// node方法找到index元素,是用for循环到的,增大了时间复杂度
return false;
}
/**
* 返回此列表中元素的列表迭代器(正确
* 序列),从列表中的指定位置开始。
* 遵守{@code List.listIterator(int)}的一般合同
*/
public ListIterator listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
// 内部类作迭代器模式
private class ListItr implements ListIterator {
private Node lastReturned;
private Node next;
private int nextIndex;
// 该类在被创建的时候,初始化expectedModCount = modCount
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
// 该方法检查modCount != expectedModCount
// 不相等抛出ConcurrentModificationException异常
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
// 获取节点元素后,nextIndex自加
nextIndex++;
return lastReturned.item;
}
// 是否有前驱节点
public boolean hasPrevious() {
return nextIndex > 0;
}
// 获取前驱节点
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
// 向前移动lastReturned和next所指向的节点对象相同
lastReturned = next = (next == null) ? last : next.prev;
// 获取节点元素后,nextIndex自减
nextIndex--;
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
// 移除lastReturned所指向的节点对象,
// 如果lastReturned未初始化或迭代器执行了add方法,
// lastReturned为null,抛出异常
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node lastNext = lastReturned.next;
// 调用了LinkedList里面的方法,改变了列表的结构,
// modCount不等于expectedModCount
// 所以下面的代码expectedModCount++;重新保证了他们的相等,
// 这样做的目的是防止外部直接调用unlink,remove,add等方法
// 改变链表的结构,导致代码出错
unlink(lastReturned);
// 如果执行了previous方法,使得next与lastReturned指向同一节点对象
// 同时索引nextIndex也在next与lastReturned之前,所以可以不用再自减,反之需要
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
// 添加元素,如已经创建好了迭代器对象,要添加元素,
// 不能直接用LinkedList对象的add等方法,要用下面的add方法
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
public void forEachRemaining(Consumer super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
// 该方法检查链表的结构是否发生改变,
// 且不是通过该迭代器add()或remove()方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
/**
* @since 1.6
*/
public Iterator descendingIterator() {
return new DescendingIterator();
}
/**
* 适配器通过ListItr.previous提供降序迭代器
* 从后往前的一个迭代器,双向链表的好处
*/
private class DescendingIterator implements Iterator {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}
// Cloneable
@SuppressWarnings("unchecked")
private LinkedList superClone() {
try {
return (LinkedList) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
/**
* 返回此{@code LinkedList}的浅表副本。 (要素
* 他们自己没有被克隆。)
*/
public Object clone() {
LinkedList clone = superClone();
// Put clone into "virgin" state
// 重置为"处女"状态
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// 使用该对象的元素初始化克隆
for (Node x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
/**
* 返回包含此列表中所有元素的数组
* 按正确的顺序(从第一个元素到最后一个元素)。
*/
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
/**
* 返回一个包含此列表中所有元素的数组
* 正确的顺序(从第一个到最后一个元素);
* 运行时类型返回的数组是指定类型的数组。
* 如果数组的大小适合,将元素填入其中。否则,
* 创建一个新的数组使用指定类型数组进行分配
* 此列表的大小。
*/
@SuppressWarnings("unchecked")
public T[] toArray(T[] a) {
// 如果数组大小小于size,通过Array的newInstance创建一个数组对象
if (a.length < size)
a = (T[]) java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node x = first; x != null; x = x.next)
result[i++] = x.item;
// 如果a数组大小大于size,则先将链表的元素添加到数组中,
// 然后将数组的下标为size的位置设置为空,但是size后面的位置上的值不变
if (a.length > size)
a[size] = null;
return a;
}
private static final long serialVersionUID = 876323262645176354L;
/**
* 将此{@code LinkedList}实例的状态保存到流中
* (即序列化)。
*/
// 实现了java.io.Serializable接口,但是被关键字transient修饰的字段,不会被序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();
// 先将size写入
s.writeInt(size);
// 以正确的顺序写出所有元素。
for (Node x = first; x != null; x = x.next)
s.writeObject(x.item);
}
/**
* 从流中重构此{@code LinkedList}实例
* (即反序列化)。
*/
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// 读入任何隐藏的序列化魔法
s.defaultReadObject();
// 因为写入的时候是先写入size,所以读取的时候,也要按照顺序读取
int size = s.readInt();
// 按正确的顺序读入所有元素。
for (int i = 0; i < size; i++)
linkLast((E) s.readObject());
}
/**
* 下面的迭代器,主要作用是将链表节点值分批放入数组
*/
@Override
public Spliterator spliterator() {
return new LLSpliterator(this, -1, 0);
}
/**
* Spliterators.IteratorSpliterator的自定义变体
*/
static final class LLSpliterator implements Spliterator {
// 批量数组大小增量,2的10次方等于1024
static final int BATCH_UNIT = 1 << 10;
// 最大批量数组大小;2的25次方等于33554432
static final int MAX_BATCH = 1 << 25;
final LinkedList list; // null OK,除非遍历
Node current; // 当前节点; null,直到初始化
int est; // 规模估计; -1直到第一次需要
int expectedModCount; // 在est设置时初始化
int batch; // 拆分的批量大小
LLSpliterator(LinkedList list, int est, int expectedModCount) {
this.list = list;
this.est = est;
this.expectedModCount = expectedModCount;
}
// 获取est的大小,如果是第一次获取,
// 该方法会同时将current、expectedModCount赋值
final int getEst() {
int s; // 强制初始化
final LinkedList lst;
if ((s = est) < 0) {
if ((lst = list) == null)
s = est = 0;
else {
expectedModCount = lst.modCount;
current = lst.first;
s = est = lst.size;
}
}
return s;
}
public long estimateSize() {
return (long) getEst();
}
//
public Spliterator trySplit() {
Node p;
int s = getEst();
// 检查链表的长度是否大于1和头节点是否为null
if (s > 1 && (p = current) != null) {
int n = batch + BATCH_UNIT;
if (n > s)
n = s;
if (n > MAX_BATCH)
n = MAX_BATCH;
// 创建一个长度为n的数组
Object[] a = new Object[n];
int j = 0;
do {
a[j++] = p.item;
} while ((p = p.next) != null && j < n);
current = p;
batch = j;
est = s - j;
return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
}
return null;
}
public void forEachRemaining(Consumer super E> action) {
Node p;
int n;
if (action == null) throw new NullPointerException();
if ((n = getEst()) > 0 && (p = current) != null) {
current = null;
est = 0;
do {
E e = p.item;
p = p.next;
action.accept(e);
} while (p != null && --n > 0);
}
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer super E> action) {
Node p;
if (action == null) throw new NullPointerException();
if (getEst() > 0 && (p = current) != null) {
--est;
E e = p.item;
current = p.next;
action.accept(e);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
}