java基础-集合框架


| 阅读 |,阅读约 14 分钟
| 复制链接:

Overview

java集合框架

简介

java集合框架是我们日常开发最常用的工具,路径为rt.jar/java/util,尤其是ArrayList和HashMap。整个集合框架的类图结构如下图:

  • 顶层主要是两大接口:Collection和Map
  • Collection下又包括三个子接口:Set、List、Queue

java集合框架

总体来说,集合框架主要包括四大体系:

  • Set:无序、不可重复的集合
  • List:有序、可重复的集合
  • Map:有映射关系的结合
  • Queue:队列集合

集合与数组的区别

对比项 集合 数组
元素数量 不确定 初始化时指定
能否表示映射 不能
元素类型 只能是对象(基本类型需要做包装) 基本类型或对象(的引用)

顶层接口

Collection

 1// rt.jar/java/util/Collection.java
 2public interface Collection<E> extends Iterable<E> {
 3    // 返回元素数量
 4    int size();
 5    // 判断集合是否为空
 6    boolean isEmpty();
 7    // 判断集合中是否有该元素
 8    // 如果待判定的元素类型兼容容器中的元素类型,抛出ClassCastException异常
 9    // 如何元素为空,但是结合不允许为空,抛出NullPointerException异常
10    boolean contains(Object o);
11    // 获取元素的迭代器
12    Iterator<E> iterator();
13    // 返回集合中所有元素的对象数组
14    Object[] toArray();
15    // 返回包含指定元素的数组
16    <T> T[] toArray(T[] a);
17    // 添加元素
18    boolean add(E e);
19    // 移除元素
20    boolean remove(Object o);
21    // 集合中是否都包含要查询的所有元素
22    boolean containsAll(Collection<?> c);
23    // 批量添加元素
24    boolean addAll(Collection<? extends E> c);
25    // 批量移除元素
26    boolean removeAll(Collection<?> c);
27    // 按条件移除元素,条件需要实现Predicate接口,重写test方法
28    default boolean removeIf(Predicate<? super E> filter) {...}
29    // 保留指定的元素
30    boolean retainAll(Collection<?> c);
31    // 清空集合
32    void clear();
33    // 判断集合是否相等
34    boolean equals(Object o);
35    int hashCode();
36    // java8新增的接口
37    @Override
38    default Spliterator<E> spliterator() {
39        return Spliterators.spliterator(this, 0);
40    }
41
42    // java8新增的接口,将集合转为流
43    default Stream<E> stream() {
44        return StreamSupport.stream(spliterator(), false);
45    }
46
47    // java8新增的接口,将集合转为并行操作的流
48    default Stream<E> parallelStream() {
49        return StreamSupport.stream(spliterator(), true);
50    }
51}

Iterator

Collection中的所有元素都可以通过Iterator遍历(迭代器),它是Collection的父接口

 1public interface Iterator<E> {
 2    // 判断集合中是否还有更多的元素
 3    boolean hasNext();
 4    // 获取集合中迭代器获取到的元素
 5    E next();
 6    // 移除集合中迭代器当前的元素
 7    default void remove() {
 8        throw new UnsupportedOperationException("remove");
 9    }
10    // java8新增的接口,对元素执行某个动作
11    default void forEachRemaining(Consumer<? super E> action) {
12      ...
13    }
14}

Map

  • map中基本的方法和collection一样
  • 内部使用Entry接口保存一个key-value实体
 1public interface Map<K,V> {
 2    // 返回元素个数
 3    int size();
 4    // 是否为空
 5    boolean isEmpty();
 6    // 是否包含某个key
 7    boolean containsKey(Object key);
 8    // 是否包含某个value
 9    boolean containsValue(Object value);
10    // 根据key获取value
11    V get(Object key);
12    // 设置key对应的value
13    V put(K key, V value);
14    // 移除某个key
15    V remove(Object key);
16    // 批量设置
17    void putAll(Map<? extends K, ? extends V> m);
18    // 清空所有数据
19    void clear();
20    // 获取所有的key集合
21    Set<K> keySet();
22    // 获取所有的value列表
23    Collection<V> values();
24    // Entry是Map的内部接口,表示map中的一个实体(key-value对)
25    Set<Map.Entry<K, V>> entrySet();
26    // 内部接口,保存key-value对
27    interface Entry<K,V> {
28        // 获取一个实体的key
29        K getKey();
30        // 获取value
31        V getValue();
32        // 设置value
33        V setValue(V value);
34        boolean equals(Object o);
35        int hashCode();
36        ...
37    }
38
39    boolean equals(Object o);
40    int hashCode();
41    // 获取key对应value,获取不到就返回默认值
42    default V getOrDefault(Object key, V defaultValue) {...}
43    // java8新增的接口, 遍历元素并对每个元素执行需要执行的动作
44    default void forEach(BiConsumer<? super K, ? super V> action) {...}
45    // java8新增的接口,对满足函数要求的元素替代为新值
46    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {...}
47    // 如果元素存在直接返回,不存在就插入
48    default V putIfAbsent(K key, V value) {...}
49    // 移除指定的key和value键值对
50    default boolean remove(Object key, Object value) {...}
51    // 替换旧值为新值,旧值必须存在,新值必须不为null
52    default boolean replace(K key, V oldValue, V newValue) {...}
53    // 替换值,不管旧值是什么
54    default V replace(K key, V value) {...}
55    // 通过给的的方法,设置新值
56    default V computeIfAbsent(K key,
57            Function<? super K, ? extends V> mappingFunction) {...}
58
59    default V computeIfPresent(K key,
60            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {...}
61
62    default V compute(K key,
63            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {...}
64
65    //
66    default V merge(K key, V value,
67            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {...}
68}

Collection子接口

Set

Set的接口和Collection基本一样。其实Set就是Collection,只不过元素不允许重复出现

 1public interface Set<E> extends Collection<E> {
 2    int size();
 3    boolean isEmpty();
 4    boolean contains(Object o);
 5    Iterator<E> iterator();
 6    Object[] toArray();
 7    <T> T[] toArray(T[] a);
 8    boolean add(E e);
 9    boolean remove(Object o);
10    boolean containsAll(Collection<?> c);
11    boolean addAll(Collection<? extends E> c);
12    boolean retainAll(Collection<?> c);
13    boolean removeAll(Collection<?> c);
14    void clear();
15    boolean equals(Object o);
16    int hashCode();
17
18    default Spliterator<E> spliterator() {...}
19}

List

List代表元素有序、可重复的集合,每个元素都有其对应的顺序索引,接口中增加了许多根据索引操作集合元素的方法

 1public interface List<E> extends Collection<E> {
 2    ...
 3    // java8新增的接口,根据operator指定的计算规则重新设置集合中所有的元素
 4    default void replaceAll(UnaryOperator<E> operator) {...}
 5    // java8新增的接口,根据Comparator参数对list集合的元素排序
 6    default void sort(Comparator<? super E> c) {...}
 7    // 获取list中的特定索引的元素
 8    E get(int index);
 9    // 替换特定位置的元素
10    E set(int index, E element);
11    // 索引位置插入元素
12    void add(int index, E element);
13    // 移除索引位置元素
14    E remove(int index);
15    // 元素在list中首次出现的索引
16    int indexOf(Object o);
17    // 元素在list中最后一次出现的索引
18    int lastIndexOf(Object o);
19    // 返回list迭代器
20    ListIterator<E> listIterator();
21    // 返回从指定的索引开始的迭代器
22    ListIterator<E> listIterator(int index);
23    // 获取指定范围的子元素列表,包括fromIndex,不包括toIndex
24    List<E> subList(int fromIndex, int toIndex);
25
26    default Spliterator<E> spliterator() {...}
27}

Queue

Queue是模拟队列的先进先出容器,不允许随机访问元素

 1public interface Queue<E> extends Collection<E> {
 2    // 队列尾部插入元素,空间不足时抛出异常
 3    boolean add(E e);
 4    // 队列尾部插入元素,空间不足不会抛出异常
 5    boolean offer(E e);
 6    // 返回并移除队列头部的元素,如果队列为空将抛出异常
 7    E remove();
 8    // 返回并移除队列头部的元素,如果队列为空将返回null
 9    E poll();
10    // 返回队列头部元素,但是不移除,队列为空抛出异常
11    E element();
12    // 返回头部元素,但是不移除,队列为空返回null
13    E peek();
14}

Set实现类

HashSet

HashSet是set的典型实现,实现了Set接口中所有方法,并没有额外方法。大多数使用Set就是使用HashSet。按照Hash算法存储集合中的元素,因此有很好的存取和查找性能。本质上是一个HashMap,value是一个静态object。HashSet有如下特点:

  • 元素排序顺序不固定
  • 线程不安全
  • 元素可以是null
  • 判断元素相等的条件:equals方法和hashCode方法返回值都相等

equals方法通过判断两个对象的地址是否相等来区分它们是否相等。hashCode的作用是获取哈希码,也称为散列码,返回一个int整型,以确定在哈希表中的索引位置

hashCode是否相等,决定了元素在HashSet中的存储位置。如果两个元素的hashcode相等,但是equals不相等,元素会以list的形式存储在相同的位置

 1public class HashSet<E>
 2    extends AbstractSet<E>
 3    implements Set<E>, Cloneable, java.io.Serializable
 4{
 5    // HashSet的底层实现是HashMap,内部定义了一个HashMap存储元素
 6    private transient HashMap<E,Object> map;
 7
 8    // 空的object,作为HashSet底层存储的HashMap中所有的value
 9    private static final Object PRESENT = new Object();
10
11    // 构造函数new一个HashMap对象
12    public HashSet() {
13        map = new HashMap<>();
14    }
15    // 这里内部使用LinkedHashMap作为底层存储结构
16    // 私有的方法,仅仅提供给LinkedHashSet使用
17    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
18        map = new LinkedHashMap<>(initialCapacity, loadFactor);
19    }
20}

LinkedHashSet

使用链表维护插入顺序,确保元素次序。其余属性和HashSet一样

 1// 只有四个构造函数
 2public class LinkedHashSet<E>
 3    extends HashSet<E>
 4    implements Set<E>, Cloneable, java.io.Serializable {
 5    // 这里调用父类的构造函数,也就是前面介绍过的内部new的LinkedHashMap来存储底层数据
 6    public LinkedHashSet(int initialCapacity, float loadFactor) {
 7        super(initialCapacity, loadFactor, true);
 8    }
 9    public LinkedHashSet(int initialCapacity) {
10        super(initialCapacity, .75f, true);
11    }
12    public LinkedHashSet() {
13        super(16, .75f, true);
14    }
15    public LinkedHashSet(Collection<? extends E> c) {
16        super(Math.max(2*c.size(), 11), .75f, true);
17        addAll(c);
18    }
19    @Override
20    public Spliterator<E> spliterator() {
21        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
22    }
23}

TreeSet

  • TreeSet是SortedSet接口的实现类,可以确保集合元素处于排序状态,TreeSet还提供了几个额外的方法
  • TreeSet线程不安全
  • 判断两个元素是否相等的标准:两个对象通过compareTo方法比较是否返回0。
  • 添加到TreeSet中的元素必须实现Comparable接口,或者通过构造函数传入自定义比较器
  • TreeSet是根据红黑树结构找到集合元素的存储位置
 1public class TreeSet<E> extends AbstractSet<E>
 2    implements NavigableSet<E>, Cloneable, java.io.Serializable
 3{
 4    // 底层使用NavigableMap存储
 5    private transient NavigableMap<E,Object> m;
 6    // value值
 7    private static final Object PRESENT = new Object();
 8
 9    public TreeSet() {
10        this(new TreeMap<E,Object>());
11    }
12    public Iterator<E> iterator() {
13        return m.navigableKeySet().iterator();
14    }
15    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
16                                  E toElement,   boolean toInclusive) {
17        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
18                                       toElement,   toInclusive));
19    }
20    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
21        return new TreeSet<>(m.headMap(toElement, inclusive));
22    }
23
24    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
25        return new TreeSet<>(m.tailMap(fromElement, inclusive));
26    }
27    // 返回子元素集合,包括from,不包括to
28    public SortedSet<E> subSet(E fromElement, E toElement) {
29        return subSet(fromElement, true, toElement, false);
30    }
31
32    public SortedSet<E> headSet(E toElement) {
33        return headSet(toElement, false);
34    }
35
36    public SortedSet<E> tailSet(E fromElement) {
37        return tailSet(fromElement, true);
38    }
39    // 返回元素进行比较的比较器,内部返回的是NavigableMap的比较器
40    public Comparator<? super E> comparator() {
41        return m.comparator();
42    }
43    // 返回set中第一个元素
44    public E first() {
45        return m.firstKey();
46    }
47    // 返回set中最后一个元素
48    public E last() {
49        return m.lastKey();
50    }
51    // 返回小于给定元素的最大元素
52    public E lower(E e) {
53        return m.lowerKey(e);
54    }
55    public E floor(E e) {
56        return m.floorKey(e);
57    }
58    public E ceiling(E e) {
59        return m.ceilingKey(e);
60    }
61    // 返回大于给定元素的最小元素
62    public E higher(E e) {
63        return m.higherKey(e);
64    }
65    public E pollFirst() {
66        Map.Entry<E,?> e = m.pollFirstEntry();
67        return (e == null) ? null : e.getKey();
68    }
69    public E pollLast() {
70        Map.Entry<E,?> e = m.pollLastEntry();
71        return (e == null) ? null : e.getKey();
72    }
73}

EnumSet

  • 是一个专门为枚举类设计的集合,所有元素都必须是枚举类中的枚举值
  • 元素是有序的
  • 线程不安全
  • 不允许加入null元素

List实现类

List接口提供了一个listIterator方法,返回ListIterator对象。 ListIterator比Iterator新增了两个功能:

  • 前向迭代功能:previous,hasPrevious
  • 向集合添加、删除元素功能:add,remove
 1public interface ListIterator<E> extends Iterator<E> {
 2    // 后向迭代
 3    boolean hasNext();
 4    E next();
 5    // 前向迭代
 6    boolean hasPrevious();
 7    E previous();
 8    // 下一个索引
 9    int nextIndex();
10    // 前一个索引
11    int previousIndex();
12    // 移除元素
13    void remove();
14    // 替换元素
15    void set(E e);
16    // 添加元素
17    void add(E e);
18}

ArrayList

  • ArrayList和Vector是List的两个典型实现,
  • 都是基于数组的实现。内部封装了一个动态的、允许再分配的Object[]数组。
  • 随机访问效率高

ArrayList和Vector的对比:

  • ArrayList:线程不安全、效率高
  • Vector:线程安全、效率低

ArrayList访问方式:

  • 迭代器(效率低)
  • for(xx x: list)
  • 索引方式
 1public class ArrayList<E> extends AbstractList<E>
 2        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
 3{
 4    // 默认容量为10
 5    private static final int DEFAULT_CAPACITY = 10;
 6    private static final Object[] EMPTY_ELEMENTDATA = {};
 7    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 8    // 底层存储结构为Object数组
 9    transient Object[] elementData; // non-private to simplify nested class access
10    // 元素数量
11    private int size;
12    // 指定容量的ArrayList
13    public ArrayList(int initialCapacity) {
14        if (initialCapacity > 0) {
15            this.elementData = new Object[initialCapacity];
16        } else if (initialCapacity == 0) {
17            this.elementData = EMPTY_ELEMENTDATA;
18        } else {
19            throw new IllegalArgumentException("Illegal Capacity: "+
20                                               initialCapacity);
21        }
22    }
23    // 不指定容量的ArrayList,默认元素数量为10
24    public ArrayList() {
25        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
26    }
27    // 扩容函数,确保能够容纳最小容量的元素数
28    public void ensureCapacity(int minCapacity) {
29        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
30            // any size if not default element table
31            ? 0
32            // larger than default for default empty table. It's already
33            // supposed to be at default size.
34            : DEFAULT_CAPACITY;
35
36        if (minCapacity > minExpand) {
37            ensureExplicitCapacity(minCapacity);
38        }
39    }
40}

Stack继承自Vector,模拟栈数据结构,线程安全的,但是性能较差,尽量少用,用LinkedList代替

LinkedList

  • LinkedList不仅仅是一个list,还实现了Deque接口,可以被当做双端队列来使用。
  • 既可以当栈使用,也可以当队列使用
  • 底层是链表实现,插入和删除元素效率高
  • 线程不安全
 1public class LinkedList<E>
 2    extends AbstractSequentialList<E>
 3    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
 4{
 5    // 链表元素数量
 6    transient int size = 0;
 7    // 链表的表头
 8    transient Node<E> first;
 9    // 链表的表尾
10    transient Node<E> last;
11    // 内部类,Node数据结构
12    private static class Node<E> {
13        // 表示集合元素值
14        E item;
15        // 指向下一个元素
16        Node<E> next;
17        // 指向上一个元素
18        Node<E> prev;
19
20        Node(Node<E> prev, E element, Node<E> next) {
21            this.item = element;
22            this.next = next;
23            this.prev = prev;
24        }
25    }
26    // 元素插入列表表头
27    public void addFirst(E e) {
28        linkFirst(e);
29    }
30    // 追加元素到队列末尾
31    public void addLast(E e) {
32        linkLast(e);
33    }
34    // 获取第一个元素
35     public E getFirst() {
36        final Node<E> f = first;
37        if (f == null)
38            throw new NoSuchElementException();
39        return f.item;
40    }
41    // 获取最后一个元素
42    public E getLast() {
43        final Node<E> l = last;
44        if (l == null)
45            throw new NoSuchElementException();
46        return l.item;
47    }
48    // 列表头部插入指定元素
49    public boolean offerFirst(E e) {
50        addFirst(e);
51        return true;
52    }
53    // 列表末尾插入指定元素
54    public boolean offerLast(E e) {
55        addLast(e);
56        return true;
57    }
58    // 获取列表第一个元素(但是不删除),如果列表为空,返回null
59    public E peekFirst() {
60        final Node<E> f = first;
61        return (f == null) ? null : f.item;
62     }
63    // 获取最后一个元素(但是不删除),如果列表为空,返回null
64    public E peekLast() {
65        final Node<E> l = last;
66        return (l == null) ? null : l.item;
67    }
68
69    // 获取列表第一个元素(并删除),如果列表为空,返回null
70    public E pollFirst() {
71        final Node<E> f = first;
72        return (f == null) ? null : unlinkFirst(f);
73    }
74    // 获取最后一个元素(并删除),如果列表为空,返回null
75    public E pollLast() {
76        final Node<E> l = last;
77        return (l == null) ? null : unlinkLast(l);
78    }
79    // 获取指定索引的Node节点
80    Node<E> node(int index) {
81        // 判断index和list中元素个数的 1/2 做比较,如果小于 size/2, 从前往后找。如果 大于 size/2, 从后往前找
82        if (index < (size >> 1)) {
83            Node<E> x = first;
84            for (int i = 0; i < index; i++)
85                x = x.next;
86            return x;
87        } else {
88            Node<E> x = last;
89            for (int i = size - 1; i > index; i--)
90                x = x.prev;
91            return x;
92        }
93    }
94}

Queue实现类

PriorityQueue

  • 优先级队列插入元素时并不是按顺序插入,而是按照元素大小重新排序,头部元素最小,尾部元素最大。
  • 底层实现用数组表达的堆数据结构
  • 不是线程安全的
  • 不允许插入null
  • 插入元素时执行以下操作:
    • 判断是否有余量
    • 调用grow增加容量
    • 调用shiftUp插入数据
 1public class PriorityQueue<E> extends AbstractQueue<E>
 2    private static final int DEFAULT_INITIAL_CAPACITY = 11;
 3
 4    // 底层实现是对象数组,堆表示数据的大小关系
 5    transient Object[] queue; // non-private to simplify nested class access
 6    // 插入元素
 7    public boolean offer(E e) {
 8        if (e == null)
 9            throw new NullPointerException();
10        modCount++;
11        int i = size;
12        if (i >= queue.length)
13            // 空间不足时,grow扩容
14            grow(i + 1);
15        size = i + 1;
16        if (i == 0)
17            queue[0] = e;
18        else
19            // 插入数据
20            siftUp(i, e);
21        return true;
22    }
23}

Deque

  • Deque是Queue的子接口,代表一个双端队列
  • LinkedList也实现了Deque接口
  • Deque也可以用来实现栈,代替古老的、性能差的Stack
 1public interface Deque<E> extends Queue<E> {
 2    // 队列头部插入元素
 3    void addFirst(E e);
 4    // 队列尾部插入元素
 5    void addLast(E e);
 6    boolean offerFirst(E e);
 7    boolean offerLast(E e);
 8    E removeFirst();
 9    E removeLast();
10    E pollFirst();
11    E pollLast();
12    E getFirst();
13    E getLast();
14    E peekFirst();
15    E peekLast();
16    boolean removeFirstOccurrence(Object o);
17    boolean removeLastOccurrence(Object o);
18    boolean add(E e);
19    boolean offer(E e);
20    E remove();
21    E poll();
22    E element();
23    E peek();
24    void push(E e);
25    E pop();
26    boolean remove(Object o);
27    boolean contains(Object o);
28    public int size();
29    Iterator<E> iterator();
30    Iterator<E> descendingIterator();
31
32}

ArrayDeque

  • 用数组实现的Deque,数组是循环数组,两端都可以索引
  • 线程不安全
  • 用作栈时,性能比Stack好
  • 用作队列时,性能比LinkedList好
 1public class ArrayDeque<E> extends AbstractCollection<E>
 2                           implements Deque<E>, Cloneable, Serializable
 3{
 4    // 底层存储数据的数组对象
 5    transient Object[] elements; // non-private to simplify nested class access
 6    // 头部索引
 7    transient int head;
 8    // 尾部索引
 9    transient int tail;
10    // 默认容量,设置时设置为2的N次方
11    private static final int MIN_INITIAL_CAPACITY = 8;
12    // 插入元素
13    public void addFirst(E e) {
14        if (e == null)
15            throw new NullPointerException();
16        // head -1 取模操作
17        elements[head = (head - 1) & (elements.length - 1)] = e;
18        if (head == tail)
19            // 头尾指针一样,说明空间满了,需要扩容
20            // 申请一个2倍数量的空间,并将原数据拷贝过去
21            doubleCapacity();
22    }
23    // 扩容空间
24    private void doubleCapacity() {
25        assert head == tail;
26        int p = head;
27        int n = elements.length;
28        // header右边元素个数
29        int r = n - p; // number of elements to the right of p
30        // 空间*2,扩充一倍
31        int newCapacity = n << 1;
32        if (newCapacity < 0)
33            throw new IllegalStateException("Sorry, deque too big");
34        Object[] a = new Object[newCapacity];
35        // 复制右半部分数据
36        System.arraycopy(elements, p, a, 0, r);
37        // 复制左半部分数据
38        System.arraycopy(elements, 0, a, r, p);
39        elements = a;
40        head = 0;
41        tail = n;
42    }
43}

Map实现类

Map存储键值对,HashMap和Hashtable是Map的经典实现。两者的区别:

  • HashMap:线程不安全、key和value可以为null
  • HashTable:线程安全、key和value不能是null

Hashtable不是HashTable,古老的代码不是很规范

HashMap的key和value判断元素是否相等的标准:

  • key:equals和hashCode的返回值都相等
  • value:只需要equals返回值相等即可

HashMap

HashMap的key元素不能重复,但是value可以重复。底层实现逻辑包括:

  • 通过"拉链法"实现哈希表
  • 哈希表是由数组+链表组成的,数组中每个元素存储的是链表的头节点
  • 元素存储到数组中的规则是:计算key的哈希值,如果hash值相同,都存入相同的数组索引,并且追加到链表的头部
  • java8中,链表长度增加到一定大小,会使用红黑树代替链表
 1public class HashMap<K,V> extends AbstractMap<K,V>
 2{
 3    // 默认容量大小16,必须为2的N次方
 4    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 5    // 最大容量大小
 6    static final int MAXIMUM_CAPACITY = 1 << 30;
 7    // 默认的加载因子,容量自动增加时的扩容阈值。当空间超过容量总值*0.75时,将hash表扩容为两倍
 8    static final float DEFAULT_LOAD_FACTOR = 0.75f;
 9    // 空间扩容的阈值
10    static final int TREEIFY_THRESHOLD = 8;
11    static final int UNTREEIFY_THRESHOLD = 6;
12    static final int MIN_TREEIFY_CAPACITY = 64;
13    // HashMap底层使用的数组,数组中的每个元素是Node,Node是内部类,在下面定义
14    transient Node<K,V>[] table;
15    // 底层存储元素的数据结构
16    static class Node<K,V> implements Map.Entry<K,V> {
17        // key值计算出来的hash值
18        final int hash;
19        // key值
20        final K key;
21        // value值
22        V value;
23        // 下一个节点指针
24        Node<K,V> next;
25        ......
26    }
27
28    // 所有的键值对的集合
29    transient Set<Map.Entry<K,V>> entrySet;
30    // 元素数量
31    transient int size;
32    // hashmap结构被修改的次数
33    transient int modCount;
34    // 阈值,= size * factor
35    int threshold;
36    final float loadFactor;
37
38    // 指定容量和加载因子的构造函数
39    public HashMap(int initialCapacity, float loadFactor) {
40      ......
41    }
42    // 包含子Map的构造函数
43    public HashMap(Map<? extends K, ? extends V> m) {
44        this.loadFactor = DEFAULT_LOAD_FACTOR;
45        putMapEntries(m, false);
46    }
47
48    // 指定容量的构造函数
49    public HashMap(int initialCapacity) {
50        this(initialCapacity, DEFAULT_LOAD_FACTOR);
51    }
52
53    // 默认构造函数
54    public HashMap() {
55        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
56    }
57    ......
58}

LinkedHashMap

  • 使用双向链表来维护key-value对保存时按照插入的次序
  • key和value都允许为空
  • key重复会覆盖,value允许重复
  • 线程非安全
  • LinkedHashMap = HashMap + LinkedList,HashMap操作数据结构,LinkedList维护插入元素的先后顺序
 1public class LinkedHashMap<K,V>
 2    extends HashMap<K,V>
 3    implements Map<K,V>
 4{
 5    // 双向循环列表的头节点
 6    transient LinkedHashMap.Entry<K,V> head;
 7    // 双向循环列表的尾节点
 8    transient LinkedHashMap.Entry<K,V> tail;
 9    // true表示最近最少使用次序,false表示插入顺序
10    final boolean accessOrder;
11
12    static class Entry<K,V> extends HashMap.Node<K,V> {
13        // before和after用于维护插入的先后顺序
14        Entry<K,V> before, after;
15        // 调用父类的Entry初始化方法
16        Entry(int hash, K key, V value, Node<K,V> next) {
17            super(hash, key, value, next);
18        }
19    }
20}

TreeMap

有序的key-value集合,通过红黑树实现,每个key-value对作为红黑树的一个节点