package java.util;
/**
*
* <p>This class is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @author Josh Bloch
* @version 1.67, 04/21/06
* @see List
* @see ArrayList
* @see Vector
* @since 1.2
* @param <E> the type of elements held in this collection
*/
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
/**
* Constructs an empty list.
*/
public LinkedList() {
header.next = header.previous = header; // 这一步很重要,也是指明了该链表是一个双向循环链表
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
/**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
if (size==0)
throw new NoSuchElementException();
return header.next.element; // header 为一个头结点,但其不存放数据,而作用是将链表的第一个结点与最后一个结点相连,header.next 表示第一个结点,header.previous 表示最后一个结点
}
/**
* Returns the last element in this list.
*
* @return the last element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getLast() {
if (size==0)
throw new NoSuchElementException();
return header.previous.element; // 原理同 getFirst 一样
}
/**
* Removes and returns the first element from this list.
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() { // 链表的删除必须指明结点,只要知道删除哪个结点,前其前面的结点的next 指向其下一个结点,其下一个结点的previous 指向其前一个结点,那么这个结点就被删除了
return remove(header.next);
}
/**
* Removes and returns the last element from this list.
*
* @return the last element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeLast() {
return remove(header.previous);
}
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
/*
所以有add 操作都是根据addBefore 操作来完成,因为其是一个双向链表,插在前面与插在后面都是一样的,可以用同一个方法来代替
链表的插入与删除一样,都是操作指定的结点,找到相应的位置后,new Entry一个新的后,新其当前位置结点的下一个结点指向newEntry
当前结点的下一个结点的previous指向newEntry,而Entry 在new的时候就已经指明了其前后的指向,这样就可以连接起来了
*/
public void addFirst(E e) {
addBefore(e, header.next); // 插入到第一个结点的前面
}
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #add}.
*
* @param e the element to add
*/
public void addLast(E e) { // 插入到header 的前面,即就是最后一个结点
addBefore(e, header);
}
/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return <tt>true</tt> if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) { // 与addlast 操作相同
addBefore(e, header);
return true;
}
/**
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
/*
结点的删除,其思路也很简单,就是找到要删除的值,然后将其删除,对于给定的参数,
我们通过header 头结点开始遍历整个链表,如果碰到相同的值就删除,一但删除,就return ,所以remove 只会删除一个值
因为是一个双向循环链表,我们可以通过 size 来控制循环,也可以通过结点,从header.next 出发,如果再次碰到header ,则表前一次循环结束,
如果Collection 集合中存放的元素,并没有约束不能存入null ,所以对null 值时有特别的要求,因为我们比较两个对象时用的是equals 方法,
如果参数是一个对象的话,它则有自己的equals 方法不会错,而如果是一个null,调用equals 方法时则会异常,所以我们要分开处理
*/
public boolean remove(Object o) {
if (o==null) {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (e.element==null) {
remove(e);
return true;
}
}
} else {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (o.equals(e.element)) {
remove(e);
return true;
}
}
}
return false;
}
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the specified
* collection's iterator. The behavior of this operation is undefined if
* the specified collection is modified while the operation is in
* progress. (Note that this will occur if the specified collection is
* this list, and it's nonempty.)
*
* @param c collection containing elements to be added to this list
* @return <tt>true</tt> if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
/**
* @param index index at which to insert the first element
* from the specified collection
* @param c collection containing elements to be added to this list
* @return <tt>true</tt> if this list changed as a result of the call
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws NullPointerException if the specified collection is null
*/
/*
addAll 思路:将Collecion集合转成数组,然后循环数组,创建相应结点,将数组值放入结点,对于该方法应用 Entry(index) 方法,其功能是返回索引为index的结点(从0开始)
插入的过程:根据 Entry(index) 返回第index的结点,(0:返回第1个,1:返回值二个)根据返回的结点找到了插入的位置,其实他是根据数组新生成一个链表,然后将这个链表
再插入到要插入的位置,他插入的位置也就是Entry 返回结点的前面,如果参数为1,Entry 返回第二个结点,插在了第二个结点的前面,其实也就相当于插到第一个结点的后面
这样效果就和插入到index 个结点的后面是一样的
返回的插入结点为successor,对于第一个生成的结点将下一个结点都指向successor,而新结点的前一个结点为prodecessor,这样就相当于每个新生的链结插入新链表的最后
然后最后将新生的链表插入到Entry 返回链表的前面,这样就完成了整个链表的加入
*/
public boolean addAll(int index, Collection<? extends E> c) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew==0)
return false;
modCount++;
Entry<E> successor = (index==size ? header : entry(index));//得到要插入的位置结点
Entry<E> predecessor = successor.previous; // 得到其前一个结点
for (int i=0; i<numNew; i++) {
Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);// 插入新的结点
predecessor.next = e;
predecessor = e;
}
successor.previous = predecessor;
size += numNew;
return true;
}
/**
* Removes all of the elements from this list.
*/
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;// 保存当前的结点
e.next = e.previous = null;
e.element = null;
e = next;
}
header.next = header.previous = header; // 新链表设置成初始状态
size = 0;
modCount++;
}
// Positional Access Operations
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
return entry(index).element;
}
/**
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
Entry<E> e = entry(index);
E oldVal = e.element;
e.element = element;
return oldVal;
}
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
addBefore(element, (index==size ? header : entry(index)));
}
/**
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
return remove(entry(index));
}
/**
* Returns the indexed entry.
*/
// 返回第 index 个结点 index=0 return header.next;
private Entry<E> entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry<E> e = header;
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
// Search Operations
/**
*
* @param o element to search for
* @return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int indexOf(Object o) {
int index = 0;
if (o==null) {
for (Entry e = header.next; e != header; e = e.next) {
if (e.element==null)
return index;
index++;
}
} else {
for (Entry e = header.next; e != header; e = e.next) {
if (o.equals(e.element))
return index;
index++;
}
}
return -1;
}
/**
* @param o element to search for
* @return the index of the last occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int lastIndexOf(Object o) {
int index = size;
if (o==null) {
for (Entry e = header.previous; e != header; e = e.previous) {
index--;
if (e.element==null)
return index;
}
} else {
for (Entry e = header.previous; e != header; e = e.previous) {
index--;
if (o.equals(e.element))
return index;
}
}
return -1;
}
// Queue operations.
/**
* Retrieves, but does not remove, the head (first element) of this list.
* @return the head of this list, or <tt>null</tt> if this list is empty
* @since 1.5
*/
public E peek() {
if (size==0)
return null;
return getFirst();
}
/**
* Retrieves, but does not remove, the head (first element) of this list.
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E element() {
return getFirst();
}
/**
* Retrieves and removes the head (first element) of this list
* @return the head of this list, or <tt>null</tt> if this list is empty
* @since 1.5
*/
public E poll() {
if (size==0)
return null;
return removeFirst();
}
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E remove() {
return removeFirst();
}
/**
* Adds the specified element as the tail (last element) of this list.
*
* @param e the element to add
* @return <tt>true</tt> (as specified by {@link Queue#offer})
* @since 1.5
*/
public boolean offer(E e) {
return add(e);
}
// Deque operations
/**
* Inserts the specified element at the front of this list.
*
* @param e the element to insert
* @return <tt>true</tt> (as specified by {@link Deque#offerFirst})
* @since 1.6
*/
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
/**
* Inserts the specified element at the end of this list.
*
* @param e the element to insert
* @return <tt>true</tt> (as specified by {@link Deque#offerLast})
* @since 1.6
*/
public boolean offerLast(E e) {
addLast(e);
return true;
}
/**
* Retrieves, but does not remove, the first element of this list,
* or returns <tt>null</tt> if this list is empty.
*
* @return the first element of this list, or <tt>null</tt>
* if this list is empty
* @since 1.6
*/
public E peekFirst() {
if (size==0)
return null;
return getFirst();
}
/**
* Retrieves, but does not remove, the last element of this list,
* or returns <tt>null</tt> if this list is empty.
*
* @return the last element of this list, or <tt>null</tt>
* if this list is empty
* @since 1.6
*/
public E peekLast() {
if (size==0)
return null;
return getLast();
}
/**
* Retrieves and removes the first element of this list,
* or returns <tt>null</tt> if this list is empty.
*
* @return the first element of this list, or <tt>null</tt> if
* this list is empty
* @since 1.6
*/
public E pollFirst() {
if (size==0)
return null;
return removeFirst();
}
/**
* Retrieves and removes the last element of this list,
* or returns <tt>null</tt> if this list is empty.
*
* @return the last element of this list, or <tt>null</tt> if
* this list is empty
* @since 1.6
*/
public E pollLast() {
if (size==0)
return null;
return removeLast();
}
/**
* Pushes an element onto the stack represented by this list. In other
* words, inserts the element at the front of this list.
*
* <p>This method is equivalent to {@link #addFirst}.
*
* @param e the element to push
* @since 1.6
*/
public void push(E e) {
addFirst(e);
}
/**
* Pops an element from the stack represented by this list. In other
* words, removes and returns the first element of this list.
*
* <p>This method is equivalent to {@link #removeFirst()}.
*
* @return the element at the front of this list (which is the top
* of the stack represented by this list)
* @throws NoSuchElementException if this list is empty
* @since 1.6
*/
public E pop() {
return removeFirst();
}
/**
* Removes the first occurrence of the specified element in this
* list (when traversing the list from head to tail). If the list
* does not contain the element, it is unchanged.
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if the list contained the specified element
* @since 1.6
*/
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
/**
* Removes the last occurrence of the specified element in this
* list (when traversing the list from head to tail). If the list
* does not contain the element, it is unchanged.
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if the list contained the specified element
* @since 1.6
*/
public boolean removeLastOccurrence(Object o) {
if (o==null) {
for (Entry<E> e = header.previous; e != header; e = e.previous) {
if (e.element==null) {
remove(e);
return true;
}
}
} else {
for (Entry<E> e = header.previous; e != header; e = e.previous) {
if (o.equals(e.element)) {
remove(e);
return true;
}
}
}
return false;
}
/**
* @param index index of the first element to be returned from the
* list-iterator (by a call to <tt>next</tt>)
* @return a ListIterator of the elements in this list (in proper
* sequence), starting at the specified position in the list
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see List#listIterator(int)
*/
public ListIterator<E> listIterator(int index) {
return new ListItr(index);
}
// ListIterator 迭代器 内部类
private class ListItr implements ListIterator<E> {
private Entry<E> lastReturned = header; // lastReturned 结点默认指向 header 结点的迭代器
private Entry<E> next; // 下一个结点
private int nextIndex; // 下一个结点的索引,其是与数据元素索引一致,第一个结点为0,然后依次
private int expectedModCount = modCount;
ListItr(int index) { // ListIterator 构造,根据提供的参数给出迭代的开始位置,如果给出参数在 size/2 的左部,则从 next = header.next开始迭代,否则,从 next =header.previous迭代
if (index < 0 || index > size) // next=header.next next = next.previous
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
if (index < (size >> 1)) {
next = header.next; //
for (nextIndex=0; nextIndex<index; nextIndex++)// next,nextIndex指向[index]引用的那个结点,
next = next.next;
} else {
next = header; // 这里为什么要next = header,而不是next = header.previous,如果只是正向遍历的话,next = header.previous是正确的,我们发现在ListItr(index) 构造参数是[0,size]
for (nextIndex=size; nextIndex>index; nextIndex--)// index指示的是[index]结点,而当[size]时并没有这个结点存在,(因为从0开始)那么为什么还要给参数size呢?
next = next.previous; // 如果参数的范围是[0,size-1],listIterator(size-1)返回最后一个结点引用的迭代,当我们向前遍历的话,就不能得到最后一个结点,因为要得到最后一个结点得执行it.next()
}
}
public boolean hasNext() { // 迭代器是否到最后与 nextIndex ! = size
return nextIndex != size;
}
public E next() {
checkForComodification();
if (nextIndex == size)
throw new NoSuchElementException();
lastReturned = next; // 用 lastReturned 记录当前结点值,next = next.next 下移,如返回第一个结点前,next = header.next,then lastReturned = next ;next=next.next; return lastReturned
next = next.next;
nextIndex++;
return lastReturned.element;
}
public boolean hasPrevious() { // listIterator(n)返回的迭代器的next 是指向第n个元素,如在执行 it.next()才是返回第n 个元素,如果next()中执行了lastReturned= next;next=next.next
return nextIndex != 0; // 迭代器与元素都是通过next()得到元素的值,而next返回的则是 当前迭代器中的next 所以指的值,然后next=next.next;
}
public E previous() { // 实际就是返回当前结点,因为next()返回的是next,而previous 返回的是next.previvous
if (nextIndex == 0)
throw new NoSuchElementException();
lastReturned = next = next.previous; // 返回next.previous
nextIndex--;
checkForComodification();
return lastReturned.element;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex-1;
}
public void remove() {
checkForComodification();
Entry<E> lastNext = lastReturned.next; // Iterator 构造时,lastReturned=head,而与lastReturned更新有关的操作只有 next(),previous(),
try { //所以在没有执行next(),previous()前,执行iterator里面的remove()方法是错误的,因为它删除的将是header
LinkedList.this.remove(lastReturned);// 调用外部类的remove方法,删除的都是lastReturned结点
} catch (NoSuchElementException e) {
throw new IllegalStateException();
}
if (next==lastReturned)// ??? 这里是什么意思?看了半天没有看懂
next = lastNext;
else
nextIndex--;
lastReturned = header; // 执行完一次后。lastReturned又重新指向了 header,所以,在执行next() or previous前,不能连续执行两次remove ,问:为什么要重新指向header?
expectedModCount++; // 因为 lastRetuned 已经被删,所以要重新指定一个新的起点
}
public void set(E e) {
if (lastReturned == header)
throw new IllegalStateException();
checkForComodification();
lastReturned.element = e;
}
public void add(E e) {
checkForComodification();
lastReturned = header; // 在添加结点后,lasterReturned 会重新指向 header
addBefore(e, next); // 添加到next()返回元素的前面,如果还是用原来的iterator 迭代的话,将不会显示出新添加的值
nextIndex++;
expectedModCount++;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
private static class Entry<E> {
E element; // 结点元素
Entry<E> next; // 结点的下一个结点
Entry<E> previous; // 结点的前一个结点
Entry(E element, Entry<E> next, Entry<E> previous) { // 在构造一个新结点的时候,因为构造的结点要放在链表中的,所以在其构造出来的时候就要指明这个结点的前一个结点和后一个结点
this.element = element; // 至于谁指向这个结点,那是在插入元素的时候完成的,因为链表插入元素时,我们要指明插入的位置,虽然默认是链表尾部
this.next = next;
this.previous = previous;
}
}
private Entry<E> addBefore(E e, Entry<E> entry) { // 将一个元素插入到 entry 结点的前面
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); // 构造新的结点,newEntry 的下一个结点是entry,前一个结点是entry.previous
newEntry.previous.next = newEntry;// 上面是将新生的结点连接上了链表,但链表并没有连接新的结点,所以 entry.previous.next=newEntry,entry.next.previous = newEntry
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
}
// 结点的删除操作,所以的删除都是调用的这个方法,只不过是参数不一样罢了,所以其定义成了 private 了,只允许类内部调用,而不提供给外部API
private E remove(Entry<E> e) {
if (e == header) // 如果是头结点,则直接抛异常
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next; // e 的前一个结点指向e 的后一个结点,e.previous.next = e.next; e 的后一个结点指向e 的前一个结点 e.next.previous = e.previous
e.next.previous = e.previous;
e.next = e.previous = null; // 这其元素指空,这样可以真正垃圾回收,避免内在泄露
e.element = null;
size--;
modCount++;
return result;
}
/**
* @since 1.6
*/
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
/** Adapter to provide descending iterators via ListItr.previous */
private class DescendingIterator implements Iterator {
final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}
/**
* Returns a shallow copy of this <tt>LinkedList</tt>. (The elements
* themselves are not cloned.)
*
* @return a shallow copy of this <tt>LinkedList</tt> instance
*/
/*
Clone 方法:先调用父类里面的clone方法得到一个Clone链表,而调用父类里面的Clone产生的链表只是与父类引用相同的对象,并没有真正克隆,
所以我们要将其引用指向一个新的对象,首先是clone 中的header 引用,我们指向一个新的Entry,即 clone.header = new Entry<E>(null,null,null);
然后对header进行初始化 clone.header.next = clone.header.previous = clone.header;clone.size=0;clone.modCount=0;
下面对链表中的结点进行赋值新的实例化,要做的就是对其 clone.add(e.element);
*/
public Object clone() {
LinkedList<E> clone = null;
try {
clone = (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
// Put clone into "virgin" state
clone.header = new Entry<E>(null, null, null);
clone.header.next = clone.header.previous = clone.header; // 将clone的新的链表初始化
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Entry<E> e = header.next; e != header; e = e.next)
clone.add(e.element);
return clone;
}
/**
* @return an array containing all of the elements in this list
* in proper sequence
*/
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Entry<E> e = header.next; e != header; e = e.next)
result[i++] = e.element;
return result;
}
/**
* @param a the array into which the elements of the list are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing the elements of the list
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this list
* @throws NullPointerException if the specified array is null
*/
public <T> T[] toArray(T[] a) {
if (a.length < size) // 如果 参数 a 表示的数组的长度小于链表的长度,就利用反射重新生成一个数组,将参数重新指向这个数组
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Entry<E> e = header.next; e != header; e = e.next)
result[i++] = e.element;
if (a.length > size)
a[size] = null;
return a;
}
private static final long serialVersionUID = 876323262645176354L;
/**
* @serialData The size of the list (the number of elements it
* contains) is emitted (int), followed by all of its
* elements (each an Object) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();
// Write out size
s.writeInt(size);
// Write out all elements in the proper order.
for (Entry e = header.next; e != header; e = e.next)
s.writeObject(e.element);
}
/**
* Reconstitute this <tt>LinkedList</tt> instance from a stream (that is
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Initialize header
header = new Entry<E>(null, null, null);
header.next = header.previous = header;
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
addBefore((E)s.readObject(), header);
}
}
/*
LinkedList 学习总结:
结构:三个内部类:
Entry:结点:三个属性: E element,Entry<E> next, Entry<E> privious
一个方法: Entry(E element,Entry<E>next,Entry<E> previous)// 结点在生成的时候都要指定其前一个结点与下一个结点
{
this.element = element;
this.next = next;
this.previous = previous;
}
ListItr 迭代器类:
Entry<E> lastReturned = header
Entry<E> next
int nextIndex = 0
构造方法: 迭代器的意义就是其实例是引用了链表中的某一个结点,然后根据这个结点遍历剩下的所有的结点,基主要的也就是其next 属性
ListIter(index index){
next = header.next;
for(int i=0;i<index;i++){
next = next.next;
nextIndex ++;
}
}
-----------------------------------
E next()方法,返回一个结点
方法概要: lastReturned = next;
next = next.next;
return lastRetuned.element;
boolean hasNext() 其是和size 相比较,return nextIndex != size
DescendingIterator :没什么好说的,就是一个ListIter 的包装
由于上面的数据结构可以从源码里直接看出,这里就不再多说了
我想说一下从里面学到的其它的内容:
1。对于链表,我们以前学的C,C++很好写出,因为里面有指针,则开始由于Java里面没有指针,所以不知道从何入手,而看了源码才知道
Java中的引用其实完全可以作为指针来使用,我们定义的Entry结点,其中的element 作为存入数据的引用,而我们的在结点中的 next,
previous 完全也是一个结点类型Entry,这样就直接可以用它们作为引用来指向前一个与下一个结点,即:Entry<E>next;Entry<E>previuos
2.Collection 中内部类的使用不能不说一下,我们可以看出上面的三个内部类的使用,其中 Entry 类是一个 private static Entry{}
而其他的两个都是private class ,他们的区别是前一个是static ,后两个非static ,为什么呢?
1.Entry 是一个表示链表中结点的类,因为我们在new LinkedList 的时候,这个类就已经有结点存在了,所以结点在Collection中
作的是一个静态结构,随着类的产生产生,所以我们要将其定义成静态的
2. 而作为迭代器的ListItr ,它是在我们调用对象的listIterator 方法后才有的迭代器对象,如果我们不调用该方法,完全就没必要
产生这个类的实例,所以要将其非static
3.对于Collection框架还有一个经典的模式:骨架类,Collection类的结构如下:
Collection 接口
AbstractCollection 抽象类(骨架类):用于实现接口中的方法,因为接口里不能有方法体,所以定义一个骨架类,为其接口提供默认方法
这样做的好处是将接口与抽象类两者接合起来
*/
java.util.LinkedList
最新推荐文章于 2024-04-10 17:04:47 发布