Java中常见集合类核心源码阅读

2023-10-16 20:58:53 浏览数 (2)

Java中常见的集合类主要有List、Set和Map。这些集合类使用广泛,因此深入了解它们的实现原理非常重要。在Java的集合类中,最常用的是ArrayList、LinkedList、HashSet和HashMap,这些集合类的实现基本都依赖于数组和链表。

一、ArrayList源码

ArrayList是Java中最常用的集合类之一,它底层使用数组实现,它的查询效率比LinkedList高。在ArrayList中,随机访问元素的时间复杂度为O(1),增加或删除元素的时间复杂度为O(n)。

在Java 8版本中,ArrayList的源码中有一些新的方法,比如spliterator(),用于提供集合的可分割性和遍历性。另外,还有sort()和replaceAll()方法,用于对集合进行排序和替换元素。

下面是ArrayList的部分源代码,用于展示ArrayList的实现原理。

代码语言:javascript复制
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    /**
     * 默认的初始化数组容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 元素实际数量
     */
    private int size;

    /**
     * 存放元素的数组
     */
    private Object[] elementData;

    /**
     * ArrayList默认构造函数
     */
    public ArrayList() {
        this.elementData = new Object[DEFAULT_CAPACITY];
    }

    /**
     * ArrayList带初始化大小的构造函数
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = new Object[]{};
        } else {
            throw new IllegalArgumentException("Illegal Capacity: " 
                                               initialCapacity);
        }
    }

    /**
     * 向ArrayList末尾添加元素
     */
    public boolean add(E e) {
        ensureCapacityInternal(size   1);  // Increments modCount!!
        elementData[size  ] = e;
        return true;
    }

    /**
     * 返回ArrayList指定下标的元素
     */
    @SuppressWarnings("unchecked")
    public E get(int index) {
        rangeCheck(index);

        return (E) elementData[index];
    }

    /**
     * 确保ArrayList容量足够
     */
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    /**
     * 确保ArrayList容量足够
     */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount  ;

        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 扩容ArrayList大小
     */
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity   (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    /**
     * ArrayList迭代器
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * 内部类Itr,ArrayList的迭代器实现
     */
    private class Itr implements Iterator<E> {
        //...
    }

    //...
}

二、LinkedList源码

LinkedList是Java中另一个常用的集合类,它底层使用双向链表实现。在LinkedList中,插入和删除元素的时间复杂度为O(1),获取元素的时间复杂度为O(n)。

与ArrayList不同,LinkedList还支持栈和队列操作,比如poll()、offer()和push()等方法,这些方法可以实现在集合的开头和结尾插入、删除元素。

下面是LinkedList的部分源代码,用于展示LinkedList的实现原理。

代码语言:javascript复制
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    /**
     * 链表长度
     */
    transient int size = 0;

    /**
     * 链表头部
     */
    transient Node<E> first;

    /**
     * 链表尾部
     */
    transient Node<E> last;

    /**
     * 构造一个空链表
     */
    public LinkedList() {
    }

    /**
     * 向链表头部插入元素
     */
    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 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;
    }

    /**
     * 链表从头向尾遍历元素
     */
    public Iterator<E> iterator() {
        return new ListItr(0);
    }

    /**
     * 内部类ListItr,链表迭代器的实现
     */
    private class ListItr implements ListIterator<E> {
        //...
    }


    /**
     * 内部类Node,链表中存储节点的实现
     */
    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;
        }
    }
}

三、HashSet源码

HashSet是Java中常用的Set集合类,它底层使用HashMap来实现。在HashSet中,元素的添加、删除和查找操作时间复杂度均为O(1)。

HashSet与HashMap实现的主要区别是,在HashSet中,添加元素是将元素添加到HashMap的key值上,value值是一个FINAL new object();

下面是HashSet的部分源代码,用于展示HashSet的实现原理。

代码语言:javascript复制
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {
    /**
     * 底层使用的HashMap实例
     */
    private transient HashMap<E,Object> map;

    /**
     * 集合元素的默认值
     */
    private static final Object PRESENT = new Object();

    /**
     * 构造一个空HashSet
     */
    public HashSet() {
        map = new HashMap<>();
    }

    /**
     * 向HashSet中添加元素
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    /**
     * 返回集合的迭代器
     */
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

    //...
}

0 人点赞