Java源码分析——java.util工具包解析(一)——ArrayList、LinkedList、Vector类解析

版权声明:博主GitHub地址https://github.com/suyeq欢迎大家前来交流学习 https://blog.csdn.net/hackersuye/article/details/84311074

    Java中,List列表类与Set集合类的共同源头是Collection接口,而Collection的父接口是Iterable接口,在Collection接口下又实现了三个常用的接口以及一个抽象方法,分别为Queue接口、List接口、Set接口以及AbstractCollection抽象类,它们之间的关系如图:
在这里插入图片描述

    而今天所讲的AbstractList抽象类及其实现类则是继承自AbstractCollection抽象类,在AbstractList抽象类中封装了对ArrayList类与LinkedList类以及Vector类的共同操作,来给三者重写,下面来分别谈谈其实现类的区别与注意事项,先上图:
在这里插入图片描述

ArrayList

    ArrayList类是列表的数组表达形式,继承了AbstracterList抽象类以及List接口、Clone接口以及序列化接口,其默认的到存贮大小是10:

private static final int DEFAULT_CAPACITY = 10;

    而且每次容量不够扩容时,是扩展到原来的1.5倍的,假如不够的话直接采用要求的容量大小,并调用Arrays的数组复制的方法来复制:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //新的容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    其实现的克隆方法是我们平常意义上的浅克隆,只是在堆区新建了空间用来一个新的ArrayList,但是并没有新建空间来存放里面的元素,里面的元素还是指向的原来的地址,其源码如下:

public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    通过以下代码验证:

		String s1=new String("1");
        String s2=new String("1");
        String s3=new String("1");
        ArrayList<String> list=new ArrayList<>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        ArrayList<String> list2=(ArrayList<String>)list.clone();
        System.out.print(list2.get(0)==list.get(0));
        //打印为true

LinkedList

    LinkedList类是列表结构的链式表达方式,与ArrayList实现了相同的接口,它的内部节点的结构如下:

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;
        }
    }

    很简单的链表节点,也定义了first、last以及size来分别记录头结点、尾节点以及链表的节点大小:

transient int size = 0;
transient Node<E> first;
transient Node<E> last;

    同时可以把LinkedList当做栈来使用,因为其方法里含有这两个方法:

	public void push(E e) {
	    addFirst(e);
	 }
    public E pop() {
        return removeFirst();
    }

    也实现了队列:

	public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
    public E element() {
        return getFirst();
    }
    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }

    push时从头结点压入,而pop时也从头结点取出,也就是实现了栈的先进后出。与ArrayList一样,LinkedList的克隆方法也是一个浅克隆。

Vector

    Vector类相当于是ArrayList的线程安全实现,它在需要对元素进行修改的方法加了synchronized关键字,实现了线程安全,比如缩小容量:

public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

    但是Vector的扩容是与ArrayList不一样的,Vector内部多了一个capacityIncrement成员变量,这个变量是由调用者传进来的,可以让程序员自己来定义,Vector每次扩容都会增加capacityIncrement大小:

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    而Stack类是Vector的子类,在Vector类的基础上实现了元素的先进后出,是一个线程安全类:

public class Stack<E> extends Vector<E> {
    public E push(E item) {
    	// addElement是个同步方法
        addElement(item);
        return item;
    }
    public synchronized E pop() {
        E  obj;
        int  len = size();
        obj = peek();
        removeElementAt(len - 1);
        return obj;
    }
}

猜你喜欢

转载自blog.csdn.net/hackersuye/article/details/84311074