Java集合类概述《二》

在上一篇文章中我们介绍了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接口
AbstractSequentialList方法截图
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&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;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();
            }
        }
    }

未完待续……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值