- // ZZ From :http://
- // hi.baidu.com/yifan_870829/blog/item/6595fb03e0c614e908fa93f0.html
- 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;
- } // 可以看到,LinkedList继承了抽象的序列链表类,并实现了List、Queue、Cloneable、Serializable接口,使LinkedList可以像队列一样进行操作,同时可以克隆和串行化,使其能够保存到文件。
- // 值得我们注意的是,在这里面声明变量时,用到了transient关键词。那么他是什么意思啊?
- // transient 关键字表示在Serializable 的时候不保存该值。这两个变量在串行化时,不需要保存。
- // Entry类到底是如何实现的呢?
- 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;
- }
- }
- // 可以看到了,Entry里面声明了变量elment,next和previous,这就是我们在数据结构中知道的一个节点类声明。这是一个双向链表,不是吗?
- public LinkedList() {
- header.next = header.previous = header;
- }
- // 构造函数。初始化链表类。将next和previous指针指向自己。
- public LinkedList(Collection<? extends E> c) {
- this();
- addAll(c);
- }
- // 用一个链表类初始化LinkedList,关于上面的红色部分,据我的理解,这个泛型类要求加入的泛型元素必须是E的子类。
- // 这个构造函数调用了默认构造函数,addAll把c添加到LinkedList中,下面会介绍这个函数。
- public E getFirst() {
- if (size==0) {
- throw new NoSuchElementException();
- }
- return header.next.element;
- }
- // 返回第一个元素。如果size==0,抛出异常,否则就返回head.next.element;
- // 通过这句话,我们似乎明白,这里的数据结构是有头结点的。
- public E getLast() {
- if (size==0) {
- throw new NoSuchElementException();
- }
- return header.previous.element;
- }
- // 返回最后一个元素。如果size==0,那么抛出异常。否则返回header.previous.element。
- // 这就是双向链表,将头结点的previous指向最后一个元素。
- public E removeFirst() {
- return remove(header.next);
- }
- public E removeLast() {
- return remove(header.previous);
- }
- public E remove(int index) {
- return remove(entry(index));
- }
- private E remove(Entry<E> e) {
- if (e == header) {
- throw new NoSuchElementException();
- }
- E result = e.element;
- e.previous.next = e.next;
- e.next.previous = e.previous;
- e.next = e.previous = null;
- e.element = null;
- size--;
- modCount++;
- return result;
- }
- // 移走元素。要移走的元素已经确定,不需再找到这个元素。所以直接移走就可以了。先用result指向要移走的元素。然后按照数据结构中的算法移走就可以了。移走后返回移走的元素。
- // modCount是在AbstractList中声明使用的。用来记录这个链表结构被修改的次数。this list has been
- public void addFirst(E e) {
- addBefore(e, header.next);
- }
- public void addLast(E e) {
- addBefore(e, header);
- }
- public boolean add(E e) {
- addBefore(e, header);
- return true;
- }
- public void add(int index, E element) {
- addBefore(element, (index==size ? header : entry(index)));
- }
- private Entry<E> addBefore(E e, Entry<E> entry) {
- Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
- newEntry.previous.next = newEntry;
- newEntry.next.previous = newEntry;
- size++;
- modCount++;
- return newEntry;
- }
- // 将元素e添加到entry前面。很简单,不用分析,相信你也明白。
- public boolean contains(Object o) {
- return indexOf(o) != -1;
- }
- public int indexOf(Object o) {
- int index = 0;
- if (o==null) {// 如果o为null
- for (Entry e = header.next; e != header; e = e.next) {
- if (e.element==null)
- return index;
- index++;
- }
- } else { //不为空,其判断是通过equals进行判断的。
- for (Entry e = header.next; e != header; e = e.next) {
- if (o.equals(e.element))
- return index;
- index++;
- }
- }
- return -1;
- }
- // 首先获得元素的索引值。如果返回-1,无这个元素。为什么要分元素是不是空这个分支呢?因为如果o是空的话,判断是通过e.element==null判断的。不为空,则通过o.equals(e.element)判断。
- public int size() {
- return size;
- }
- // 返回大小。
- 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;
- }
- // 也比较容易理解。不做解释了。
- public boolean addAll(Collection<? extends E> c) {
- return addAll(size, c);
- }
- public boolean addAll(int index, Collection<? extends E> c) {
- if (index < 0 || index > size)// 如果要插入的位置>size或小于0,异常。
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+size);
- Object[] a = c.toArray();// 将集合中的元素转化为数组。
- int numNew = a.length;// 返回数组长度
- if (numNew==0)// 如果是0的话,遗憾,无法添加了
- return false;
- modCount++;// 不是0的话,ok,修改计数器加1
- Entry<E> successor = (index==size ? header : entry(index));// 如果index==size,那么successor=header
- Entry<E> predecessor = successor.previous;// 获得前一个处理元素
- for (int i=0; i<numNew; i++) {// 对于数组每一个元素,生成entry类,加入到链表中。
- Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
- predecessor.next = e;
- predecessor = e;
- }
- successor.previous = predecessor;
- size += numNew;
- return true;
- }
- // 如上注解。
- public void clear() {
- Entry<E> e = header.next;
- while (e != header) {
- Entry<E> next = e.next;// 记录e的next
- e.next = e.previous = null;// 去掉e的next和previous
- e.element = null;// 去掉自己元素。
- e = next;// 处理下一个节点
- }
- header.next = header.previous = header;
- size = 0;
- modCount++;
- }
- // 将链表清空。不用解释了。很简单。不过,我们通过这个方法明白一点,要真正的销毁对象,光靠垃圾回收机制是不行的。像这里,给没有用的引用赋空值,使内存中的实体对象没有指针,而加快内存的回收。
- public E get(int index) {
- return entry(index).element;
- }
- 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)) {// 如果index小于size的一半
- for (int i = 0; i <= index; i++)
- e = e.next;
- } else {// 不小于的话,ok,从后面找。
- for (int i = size; i > index; i--)
- e = e.previous;
- }
- return e;
- }
- // 多么好的算法啊。如果要找的元素在前半部分,那就从头找,如果在最后那么就从尾开始找。获得size的一半也很节省cpu消耗,采用移位的方式,值得学习。
- public E set(int index, E element) {
- Entry<E> e = entry(index);
- E oldVal = e.element;
- e.element = element;
- return oldVal;
- }
- // 不再解释。很简单。
- // 下面的分析关系到了LinkedList的遍历、持久化、克隆等相关主题。
- public ListIterator<E> listIterator(int index) {
- return new ListItr(index);
- }
- // 返回一个从index开始的遍历器。
- private class ListItr implements ListIterator<E> {
- private Entry<E> lastReturned = header;// 让这里面的参数初始化,最后一个返回的元素。
- private Entry<E> next;// 下一个元素的指针
- private int nextIndex;// 下一个元素的索引
- private int expectedModCount = modCount;// 等于原来类中的修改次数
- ListItr(int index) {// 构造函数
- if (index < 0 || index > size)// 如果给的index不正确
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+size);
- if (index < (size >> 1)) {// 如果index<size的一半
- next = header.next;// 找到index所指的元素
- for (nextIndex=0; nextIndex<index; nextIndex++)
- next = next.next;
- } else {
- next = header;// 从后面遍历,找到所要的元素
- for (nextIndex=size; nextIndex>index; nextIndex--)
- next = next.previous;
- }
- }
- public boolean hasNext() {// 判断有没有下个元素
- return nextIndex != size;
- }
- public E next() {获得下一个元素
- checkForComodification();
- if (nextIndex == size)
- throw new NoSuchElementException();
- lastReturned = next;
- next = next.next;
- nextIndex++;
- return lastReturned.element;
- }
- public boolean hasPrevious() {
- return nextIndex != 0;
- }
- public E previous() {
- if (nextIndex == 0)
- throw new NoSuchElementException();
- lastReturned = next = 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;
- try {
- LinkedList.this.remove(lastReturned);
- } catch (NoSuchElementException e) {
- throw new IllegalStateException();
- }
- if (next==lastReturned)
- next = lastNext;
- else
- nextIndex--;
- lastReturned = header;
- expectedModCount++;
- }
- public void set(E e) {
- if (lastReturned == header)
- throw new IllegalStateException();
- checkForComodification();
- lastReturned.element = e;
- }
- public void add(E e) {
- checkForComodification();
- lastReturned = header;
- addBefore(e, next);
- nextIndex++;
- expectedModCount++;
- }
- final void checkForComodification() {//
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
- }
- //上面的这个类是定义在LinkedList中的私有类。他实现了ListIterator具体的分析参照上面的注释。
- public Iterator<E> descendingIterator() {
- return new DescendingIterator();
- }
- 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();
- }
- }
- //上面的函数和类仍然返回不同的遍历器。不再解释。
- //不过DescendingIterator 是递减的遍历器。可以注意到他的next()、hasNext()方法的不同。
- 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.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;
- }
- 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;
- }
- // 转化成数组。
- public <T> T[] toArray(T[] a) {
- // 如果a太小了,那么就在重新给a分配空间吧。
- if (a.length < size)
- 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长了,a【size】=null,使不能访问后面的元素。
- a[size] = null;
- return a;
- }
- private static final long serialVersionUID = 876323262645176354L;
- 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);
- }
- 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);
- }
- }
- // 不再说明,很容易理解。就是先写入size,再写入每一个数据,读出也一样,先读取size,再读取对象。
java LinkedList分析(ZZ)
最新推荐文章于 2024-08-23 15:54:50 发布