int indexOF(T e):
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index {@code i} such that
* (o==null?get(i)==null:o.equals(get(i))),
* or -1 if there is no such index.
*
* @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(T e){
int index = 0;
if(e == null){
for(Node<T> x = first;x != null;x = x.next){
if(x.data == null)
return index;
index++;
}
}
else{
for(Node<T> x = first;x != null;x = x.next){
if(e.equals(x.data))
return index;
index++;
}
}
return -1;
}
indexOf()是找到第一个Node.data = e的节点,e == null || e == Object两种情况都要考虑。。。 找不到返回-1
int lastIndexOf():
/**
* Returns the index of the last occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the highest index {@code i} such that
* (o==null?get(i)==null:o.equals(get(i))),
* or -1 if there is no such index.
*
* @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(T e){
int index = size;
if(e == null){
for(Node<T> x = last; x != null; x = x.next){
if(x.data == null)
return index;
index--;
}
}else{
for(Node<T> x = last; x != null; x= x.next){
if(e.equals(x.data))
return index;
index--;
}
}
return -1;
}
这个是最后出现的Node.data == e的结点,原理同上
// Queue Operations
/**
* Retrieves(找回), but does not remove, the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public T peek(){
final Node<T> f = first;
return (f == null)? null:f.data;
}
/**
* 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 T Element(){
return getFirst();
}
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public T poll(){
final Node<T> f = first;
return (f == null)? null:unlinkFirst(f);
}
/**
* 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 T remove(){
return removeFirst();
}
/**
* Adds the specified element as the tail (last element) of this list.
*
* @param e the element to add
* @return {@code true} (as specified by {@link Queue#offer})
* @since 1.5
*/
public boolean offer(T e){
return add(e);
}
看吧,其实源代码大家也是可以写出来的。。 不难,都是前面方法的封装~~~
下面就直接来看List迭代器的设计学习一下它的思想,我们才能更好的使用:
private class LinkedListIterator implements java.util.ListIterator<T>{
private Node<T> lastReturned = null;
private Node<T> next ;
private int nextIndex;
private int expectedModCount = modCount;
public LinkedListIterator(){
}
public LinkedListIterator(int index){
// assert checkPositionIndex(index)
next = (index==size)?null:getNode(index);
nextIndex = index;
}
@Override
public boolean hasNext() {
return nextIndex < size;
}
public T next(){
checkForModification();
if(!hasNext())
throw new java.util.NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.data;
}
public boolean hasPrevious(){
return nextIndex > 0;
}
public T previous() {
checkForModification();
if(!hasPrevious())
throw new java.util.NoSuchElementException();
lastReturned = next = (next == null)?last:next.prev;
nextIndex--;
//因为next移动的位置已经在当前迭代元素的下一个位置,所以不用next = next.prev
return lastReturned.data;
}
public int nextIndex(){
return nextIndex;
}
public int previousIndex(){
return nextIndex - 1;
}
public void remove(){
checkForModification();
if(lastReturned == null)
throw new IllegalStateException();
<span style="font-family: Arial, Helvetica, sans-serif;">Node<T> lastNode = lastReturned.next;</span><pre name="code" class="java"> unlink(lastReturned);
if(next == lastReturned){
//当只调用了一次previous()方法next == lastReturn,其他时候lastReturn = next.prev
next = lastNode;
}else{
nextIndex--;
}
lastReturned = null;
expectedModCount++;
} public void set(T e){ if(lastReturned == null) throw new IllegalStateException(); checkForModification(); lastReturned.data = e; } public void add(T e){ checkForModification(); lastReturned = null; if(next == null) linkLast(e); else linkBefore(e,next); nextIndex++; expectedModCount++; } final void checkForModification(){if(expectedModCount != modCount){throw new java.util.ConcurrentModificationException();}}}
} public void set(T e){ if(lastReturned == null) throw new IllegalStateException(); checkForModification(); lastReturned.data = e; } public void add(T e){ checkForModification(); lastReturned = null; if(next == null) linkLast(e); else linkBefore(e,next); nextIndex++; expectedModCount++; } final void checkForModification(){if(expectedModCount != modCount){throw new java.util.ConcurrentModificationException();}}}
首先,当我们声明一个LinkedListIterator内部类时,编译器将添加一个外部类对象的的一个隐式引用,该对象引起内部类的构造。在这个LinkedListIterator的设计中 private int expectedModCount = MyLinkedList.this.modCount这里就是一个内部类应用的实例,类与类之间的关联可以是is-a,也可以是inner-outer 、nested总之我们需要灵活运用。我们可以知道在api中构造listIterator时,必须传入一个index,也就是从当前结点开始的迭代器,在new LinkedListIterator(index)时,先在堆内LinkedListiterator对象分配足够的空间,这块存储空间会被清零,这就自动的将LinkedListIterato对象中的所有基本类型设置成默认值,引用类型置null,接着执行所有出现在字段定义处的初始化动作,然后执行构造器。这时每个LinkedListIterato对象expectedModCount都被赋上LinkedList中的modCount(List结构修改次数),next ->currrentNode ,nextInt = currentIndex ,lastReturned = null(它的作用就是用来判断拿到Data)
next()方法就是返回lastReturned.data,同时向后更新next,preivous()则恰好相反~
remove方法这里还有点需要注意:
<span style="white-space:pre"> </span> Node<T> lastNode = lastReturned.next;
unlink(lastReturned);
if(next == lastReturned){
//当只调用了一次previous()方法next == lastReturn,其他时候lastReturn = next.prev
next = lastNode;
}else{
nextIndex--;
}
lastReturned = null;
expectedModCount++;
这里有可能出现这种情况,拿到迭代器后先执行一次previous()方法, lastReturned = next = (next == null)?last : last.prev ; 这时候就有 next == lastReturned的情况,next = lastNode 更新next指针。而先执行next方法,在remove的时候就只需要更新nextInt索引(减一,因为在next方法中已经将nextInt移动到lastReturned的下一个结点的索引)
最后需要注意的是:lastReturned的使用,当没有用previous和next迭代时,lastReturned == null,这时使用remove,set是会抛出IllegalStateException.
java api文档中还提供了逆序的迭代器 Iterator<T> descendingIterator():
/**
* Adapter to provide descending iterators via ListItr.previous
*/
private class DescendingIterator implements Iterator<T>{
final LinkedListIterator itr = new LinkedListIterator(size());
@Override
public boolean hasNext() {
return itr.hasPrevious();
}
@Override
public T next() {
return itr.previous();
}
@Override
public void remove() {
itr.remove();
}
@SuppressWarnings({ "unchecked" })
private MyLinkedList<T> superClone() {
try {
return (MyLinkedList<T>) super.clone();
} catch (CloneNotSupportedException e) {
//该异常指示 Java 虚拟机中出现一些意外的内部错误
throw new InternalError();
}
}
/**
* Returns a shallow copy of this {@code LinkedList}. (The elements
* themselves are not cloned.)
*
* @return a shallow copy of this {@code LinkedList} instance
*/
public Object clone(){
MyLinkedList<T> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.modCount = 0;
clone.size = 0;
// Initialize clone with our elements
for(Node<T> x = first;x != null; x=x.next ){
clone.add(x.data);
}
return clone;
}
/**
* Returns an array containing all of the elements in this list
* in proper sequence (from first to last element).
*
* <p>The returned array will be "safe" in that no references to it are
* maintained by this list. (In other words, this method must allocate
* a new array). The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all of the elements in this list
* in proper sequence
*/
@SuppressWarnings("unused")
public Object[] toArray(){
Object[] result = new Object[size];
int i = 0;
for(Node<T> x = first; x != null;x = x.next)
result[i++] = x.data;
return result;
}
}
这里大家其实可以看出DescendingIterator其实还是使用LinkedListIterator里面的方法,本质上还是一样的,至于其他的方法大家可以看看。。
最后,作为一个合格的程序员,我想说下上面的代码是最基础也是最重要的,希望大家能熟悉熟悉再熟悉~~~~
---愿与诸君共进步,Judy