在上一篇文章中我们介绍了Java集合框架的大致结构,然后分析了ArrayList的源码。然后这里给出三种遍历ArrayList的方法:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");
//第一种遍历方法使用foreach遍历List
for (String str : list) { //也可以改写for(int i=0;i<list.size();i++)这种形式
System.out.println(str);
}
//第二种遍历,把链表变为数组相关的内容进行遍历
String[] strArray=new String[list.size()];
list.toArray(strArray);
for(int i=0;i<strArray.length;i++) //这里也可以改写为foreach(String str:strArray)这种形式
{
System.out.println(strArray[i]);
}
//第三种遍历 使用迭代器进行相关遍历
Iterator<String> ite=list.iterator();
while(ite.hasNext())
{
System.out.println(ite.next());
}
}
}
ArrayList之后就是List的另一种实现:
LinkedList
LinkList的链式线性表的特点为:适合于在链表中间需要频繁进行插入和删除操作。
LikedList的链式线性表的缺点为:随机访问速度较慢。查找一个元素需要从头开始一个个的找。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
这里我们看到LinkedList是从AbstractSequentialList继承而来,然后实现了List和Deque接口
这里Deque给LinkedList提供了与队列相关的操作
LinkedList中使用双向链表来实现队列的具体功能,下面看一下在LinkedList中链表节点的具体实现:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
//只有一个构造函数,需要将节点具体值,和前一个指针和后一个指针传入构造函数。
然后我们开始看LinkedList的构造函数
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
//这里提供了两个构造函数,一个是无参构造函数,什么操作也没有。
//一个是传入一个集合对象的构造函数,首先执行空参构造函数,在讲传入的集合对象添加到列表中。
然后是LinkeList的get方法
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
/**
* Returns the last element in this list.
*
* @return the last element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
transient Node<E> first;
transient Node<E> last;
//在LinkedList的内部定义了两个变量分别指向LinkedList中双向链表的头结点和尾节点。
//获取时直接判断头结点或者尾节点是否有值,若果为空抛出一个异常。否则返回具体的值
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//根据传入参数返回相应节点的值。首先根据传入的参数值,判断参数是否正确,
//如果不正确则抛出异常。如果正确则在队列中查找相关值。
//注意在查找的时候使用了一个小技巧,如果传入参数的大小小于链表长度的一半头结
//点开始查找,否则从尾节点开始。
然后就是remove一系列的方法
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* 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() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
//这里提供了两个方法,一个是移除头结点,一个是移除尾节点。都会先进行判断当前要移除的节点是否存在。然后调用unlink*()方法进行移除。
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
//移除头结点和尾节点的方法都是差不多的,首先用一个变量储存该节点的上一个或者下一个,然后判断该节点是否为空,然后进行相应操作。
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//这个方法根据传入的item的值来删除相应的节点,首先判断item的值是否为空,如果为空进行一种操作,不为空的时候进行另一种操作。因为如果不分开处理,在使用一个null调用下面的equals方法的时候会抛出空指针异常。
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
//这个方法根据传入参数的索引删除相应的节点,首先检查参数是否正确,前面写过了,这里就不再赘述。然后使用node()方法获取相应的节点的item的值,这个方法在前面的get(int)中曾经使用过。然后将获得的item的值调用unlink来移除相应的节点。
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> 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;
}
然后是相应的一套add方法
public void addFirst(E e) {
linkFirst(e);
}
//这里直接调用linkFirst(e)方法
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
//首先获取当前头结点的值,然后新建一个节点。然后进行判断,如果当前节点是这个链表的第一个节点,那么就将尾节点的值指向当前节点。否则以前节点的上一个节点指针指向当前节点。
public void addLast(E e) {
linkLast(e);
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
//这里与插入头结点是一样的。
public boolean add(E e) {
linkLast(e);
return true;
}
//这个插入方法实际就是插入尾节点
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//这个方法根据传入的index和相应的item在链表中插入相关的值,首先判断当前index是否正确。如果正确则判断是否是插入到尾节点,如果是则调用linkLast(),如果不是在调用linkBefore()方法。
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
然后还有两个方法就是统计元素在链表中的位置
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
/**
* 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
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* 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(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
然后还有就是一些从Deque实现而来的方法
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//返回当前链表的第一个元素但是不删除
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//返回链表的第一个元素并且删除
public boolean offer(E e) {
return add(e);
}
//在链表的末尾插入一个节点,入队
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//在链表的头上插入一个元素
public boolean offerLast(E e) {
addLast(e);
return true;
}
//在链表的尾部插入一个元素
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
然后就是迭代方法
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
//Itr类,实现了Iterator接口,实现了基本的遍历方法
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
//继承自Itr,扩展了一些新的方法
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
未完待续……