java集合框架概览

224 阅读10分钟

一、概述

\qquadJAVA所有集合类都位于java.util包下,主要由两个接口派生而出:CollectionMap

  1. Collection是java集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java平台不提供这个接口任何直接的实现。其中的子接口Set是一个无序不重复的集合,无法按索引取出指定的元素。而子接口List是一个有序可重复集合,你可以通过它的索引来访问任何元素,List更像长度动态变换的数组。
  2. Map是一个以键值对保存数据的集合,key不可以重复(如果重复则新key的值会覆盖旧key的值),value可重复。

二、Collection 接口

1. Set 接口

1.1 HashSet

在这里插入图片描述 \qquadHashSet 的底层是基于 HashMap 来实现的,使用其 key 来存储集合元素,对应的velue全部是空的 Object 对象,从底层实现来看不难得出这是一个无序且不允许有重复元素的集合。由于主要是基于 HashMap 来实现,所以这个集合本身的复杂度并没有多少,基本都是调用 HashMap 的API。 主要特性: 非线程安全无序不重复元素可null 应用场景: \qquad一般情况下,可以考虑用来进行元素的去重。 主要实现:

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
    // 底层采用 HashMap 进行数据存储
    private transient HashMap<E,Object> map;
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    ...
}

添加元素: 重点看注释这句:If this set already contains the element, the call leaves the set unchanged and returns 如果此集合已包含元素,则调用将离开集合保持不变并返回

    /**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     * 
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

删除元素:

    /**
     * Removes the specified element from this set if it is present.
     * More formally, removes an element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
     * if this set contains such an element.  Returns <tt>true</tt> if
     * this set contained the element (or equivalently, if this set
     * changed as a result of the call).  (This set will not contain the
     * element once the call returns.)
     *
     * @param o object to be removed from this set, if present
     * @return <tt>true</tt> if the set contained the specified element
     */
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

1.1.1 LinkedHashSet

LinkedHashSet 的UML图:

在这里插入图片描述 LinkedHashSet 也是 Set 集合的一个实现,具有 Set 集合不重复的特点,同时具有可预测的迭代顺序,也就是我们插入的顺序。

	// 自身的构造方法
	public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }
	// 调用的父类 HashSet 构造方法 👇👇👇
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

由此可见其有序性是基于 LinkedHashMap 的实现。

主要特性: 非线程安全有序不重复元素可null 应用场景: \qquad相较于 HashSet 来说,LinkedHashSet 增加了顺序性,所以可以用在要求迭代顺序和插入顺序一致的场景。 主要实现: 参考 HashSet 。

1.2 TreeSet

TreeSet 的UML图: 在这里插入图片描述 TreeSet 是 SortedSet 接口实现类,是一种排序集合,该对象中只能添加一种类型元素,否则,会抛出java.lang.ClassCastException异常;它采用红黑树这种数据结构存储集合元素。 主要特性: 非线程安全有序不重复元素非null 应用场景: 需要快速查找的有序集合的时候可以使用。 主要实现:

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    /**
     * The backing map. 这个NavigableMap接口提供了在映射条目之间导航的功能
     */
    private transient NavigableMap<E,Object> m;

    // Dummy value to associate with an Object in the backing Map
    // 要与 map 图中的对象关联的虚拟值,在add方法中设置的固定value值
    private static final Object PRESENT = new Object();
    ...
}

添加元素:

    /**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element {@code e} to this set if
     * the set contains no element {@code e2} such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns {@code false}.
     ...
     */
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

删除元素:

/**
     * Removes the specified element from this set if it is present.
     * More formally, removes an element {@code e} such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
     * if this set contains such an element.  Returns {@code true} if
     * this set contained the element (or equivalently, if this set
     * changed as a result of the call).  (This set will not contain the
     * element once the call returns.)
     ...
     */
    public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

2. List 接口

2.1 ArrayList

ArrayList 的UML图: 在这里插入图片描述 ArrayList 可以看作是存储空间可变的数组主要特性: 非线程安全有序可重复元素可null查询快但增删慢 应用场景: 在查询多增删少的场景下可以使用。 主要实现:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity. 默认的容量大小为10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances. 用于空实例的共享空数组实例
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 用于默认大小的空实例的共享空数组实例。
     * 我们将其与EMPTY_ELEMENTDATA区分开来,以了解当添加第一个元素
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

添加元素:

/**
     * Appends the specified element to the end of this list.
     * 追加指定的元素到集合的末尾
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!重要检查点
        elementData[size++] = e;
        return true;
    }
    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     * 向指定位置插入元素,如果当前指定的位置已经有元素了,则将该位置之后的所有元素往后移,然后将新元素
     * 放置到指定位置上。
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!重要检查点
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

删除元素:

	/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     * 删除指定位置的元素,然后将该位置之后的元素统一向左移动一个位置。
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
    ...
    }

	/**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     * 删除指定元素。如果该元素存在的话,删除遍历到的第一个出现的匹配值,如果不存在则不会有什么影响。
     * 通常情况下会删除集合中所有匹配值中索引值最小的一个。
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
    public boolean remove(Object o) {
    ...
    }

2.2 LinkedList

LinkedList 的UML图 在这里插入图片描述 LinkedList 的底层采用双向链表来存储数据,所以插入删除效率高,但是查找效率较低。另外它还实现了栈和队列的操作方法,因此也可以作为栈、队列和双端队列来使用。 主要特性: 非线程安全有序可重复元素可null增删快但查询慢 应用场景: 与ArrayList 相对应的,在查询少增删多的场景下可以使用。 主要实现:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    /**
     * Pointer to first node. 前驱元素
     * 这里的 transient 关键字的主要作用就是让某些被transient关键字修饰的成员属性变量不被序列化
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.后继元素
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

添加元素:

    /**
     * Appends the specified element to the end of this list.
     * 将指定元素添加至集合的末尾。
     * <p>This method is equivalent to {@link #addLast}.
     * 该方法几乎等同于 addLast 方法
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

删除元素:

	/**
     * Retrieves and removes the head (first element) of this list.
     * 从链表头部删除元素
     * @return the head of this list
     * @throws NoSuchElementException if this list is empty
     * @since 1.5
     */
    public E remove() {
        return removeFirst();
    }
    /**
     * Removes the element at the specified position in this list.  Shifts any
     * subsequent elements to the left (subtracts one from their indices).
     * Returns the element that was removed from the list.
     * 按指定的索引位置删除元素
     * @param index the index of the element to be removed
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
	...

三、Map 接口

3.1 HashMap

作为Doug Lea (李二狗)老爷子的作品,常常是面试的重灾区,没办法,谁让人家设计的优秀呢?🤭 在这里插入图片描述 HashMap 最早在 JDK 1.2 中就出现了,底层是基于散列算法实现,源码的复杂度也是挺高的,值得细细品读。在JDK1.8中涉及到的:散列表实现、扰动函数、初始化容量、负载因子、扩容元素拆分、链表树化、红黑树等等实现后续章节专门来讲,欢迎持续关注😄主要特性: 非线程安全无序可重复元素可null 应用场景: 在需要存储键值对的场景下适合使用,比如map接参大法主要实现:

添加元素:

    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     * 向集合中插入指定的key和value键值对,如果key已经存在,则新的value值会覆盖旧值。
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    ...

获取元素:

    /**
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     *
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise
     * it returns {@code null}.  (There can be at most one such mapping.)
     *
     * <p>A return value of {@code null} does not <i>necessarily</i>
     * indicate that the map contains no mapping for the key; it's also
     * possible that the map explicitly maps the key to {@code null}.
     * The {@link #containsKey containsKey} operation may be used to
     * distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

删除元素:

    /**
     * Removes the mapping for the specified key from this map if present.
     *
     * @param  key key whose mapping is to be removed from the map
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }

3.2 ConcurrentHashMap

在这里插入图片描述 主要特性: 线程安全无序可重复元素不可null 应用场景: 在多线程环境下,使用 HashMap 进行 put 操作时存在丢失数据的情况,为了避免这种 bug 的隐患,建议使用ConcurrentHashMap 代替 HashMap。 主要实现: 添加元素:

    /**
     * Maps the specified key to the specified value in this table.
     * Neither the key nor the value can be null.
     * 在表中映射特定的key和value,key和value都不可为空
     * <p>The value can be retrieved by calling the {@code get} method
     * with a key that is equal to the original key.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with {@code key}, or
     *         {@code null} if there was no mapping for {@code key}
     * @throws NullPointerException if the specified key or value is null
     */
    public V put(K key, V value) {
        return putVal(key, value, false);
    }

获取元素:

    /**
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     * 返回指定的key对应的value值,如果匹配不到则返回null
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code key.equals(k)},
     * then this method returns {@code v}; otherwise it returns
     * {@code null}.  (There can be at most one such mapping.)
     *
     * @throws NullPointerException if the specified key is null
     */
    public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
        int h = spread(key.hashCode());
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) {
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }
            else if (eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }

删除元素:

    /**
     * Removes the key (and its corresponding value) from this map.
     * This method does nothing if the key is not in the map.
     * 从集合中删除元素,如果这个key不在集合内,也不会有什么影响。
     * @param  key the key that needs to be removed
     * @return the previous value associated with {@code key}, or
     *         {@code null} if there was no mapping for {@code key}
     * @throws NullPointerException if the specified key is null
     */
    public V remove(Object key) {
        return replaceNode(key, null, null);
    }

总结

本文只是对Java的集合体系做一个大致的介绍,后续章节会针对常用和面试高频的一些集合进行详细的分析。
欢迎点赞收藏关注🤭