Java 探究集合List、Map、Set底层的数据结构【钢镚核恒】

Java 集合

简介

  • 集合 (collection)是存储对象的容器。例如:6个人一个团队(集合)
  • 集合与数组类通,数组是存储具体数据的容器。集合的底层有用到数组

这篇文章是加深对集合的理解,探究各种集合的数据结构,让我们脑海有一个清晰地图像
探究步骤很简单,从添加数据的方法开始,在方法里面找到用什么保存数据的,就知道是啥咯
另外建议大家手动翻源码!

在这里插入图片描述

List

List 是基础接口,没有什么数据结构,他只是定义了一些基本的方法。包括Set,Map也是一样的

这是List 源码中的部分方法,都是我们常常会用到的

public interface List<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Object[] toArray();
    Iterator<E> iterator();
    boolean add(E e);
}

ArrayList

ArrayList 就是 一个 Object[] 数组

public boolean add(E e) {
    ensureCapacityInternal(size + 1); 
    elementData[size++] = e;
    return true;
}

transient Object[] elementData; 

LinkedList

LinkedList 就下面那个 Node 节点,是一个双向的链表结构

public boolean add(E e) {
    linkLast(e);
    return true;
}

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

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

Vector

Vector 也是一个 Object[] 数组

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

protected Object[] elementData;

Stack

Stack 继承了 Vector,因此 push() 也加了 synchronized 是同步的。

Stack 是(栈)的数据结构,就是一个桶,先进后出的特点。

Map

HaspMap

  • HaspMap 是 Map 接口 内部的 Entry<K,V> 接口
  • 从Node的结构可以看出,是一个单向链表
  • 存储使用数组结构,Node<K,V>[] table;
  • 所以,HaspMap 的数据结构是 数组+单向链表
  • 另外当链表长度 >=7 的时候变成红黑树结构
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // tab = table 是下面的成员数组
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    
    // >=7 的时候变成红黑树结构
    if (binCount >= TREEIFY_THRESHOLD - 1)
        treeifyBin(tab, hash);
    
    return null;
}

static final int TREEIFY_THRESHOLD = 8;
// 数组结构
transient Node<K,V>[] table;
// Node链表结构
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
}

在这里我简单的说一下 HaspMap 添加数据的原理:

首先对key取hash值,作为Node 数组的下标,不存在会直接创建新的Node节点,存在继续判断key,存在则覆盖值,不存在就在Node链表后面增加

HashTable

  • HashTable 是一个 Entry<?,?>[]数组
  • 利用synchronized 关键字,实现同步,保证多线程安全
public synchronized V put(K key, V value) {
    Entry<?,?> tab[] = table;

    addEntry(hash, key, value, index);
    return null;
}
private transient Entry<?,?>[] table;

TreeMap

  • TreeMap 是红黑树结构,时间复杂度为 Olog(n)
  • TreeMap 是有序的,通过Comparator的compare进行排序
public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key);
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    return null;
}
// Entry<K,V>
private transient Entry<K,V> root;
// 
static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left;
        Entry<K,V> right;
        Entry<K,V> parent;
        boolean color = BLACK;
    
        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }
}

ConcurrentHashMap

  • ConcurrentHashMap 数据结构和HashMap一致
  • 主要通过 Segment<K,V> 分段锁来保证线程安全
  • 还采用了 volatile 关键字实现细微的同步
private void writeObject(java.io.ObjectOutputStream s)
        @SuppressWarnings("unchecked")
        Segment<K,V>[] segments = (Segment<K,V>[])
            new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL]; 
}

static class Segment<K,V> extends ReentrantLock implements Serializable {
    private static final long serialVersionUID = 2249069246763182397L;
    final float loadFactor;
    Segment(float lf) { this.loadFactor = lf; }
}

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;

    Node(int hash, K key, V val, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.val = val;
        this.next = next;
    }
}

transient volatile Node<K,V>[] table;

Set

HashSet

  • HashSet 就是一个 HashMap。HashMap的key存放值,value存放Object对象

  • HashSet 特点是不重复,也正是利用了HashMap的数据结构的特点,它key是不会重复的。如果不理解先看上面的HashMap知识

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

private static final Object PRESENT = new Object();

TreeSet

  • TreeSet 就是一个 TreeMap,用来排序数据的
  • TreeSet 自定义排序规则,可以使用第二构造器,传入Comparator,重写compare() 比较规则
public TreeSet() {
    this(new TreeMap<E,Object>());
}

public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}

Collections

  • Collections 是集合的工具类,即Collection接口的包装器
  • 主要提供一些对集合进行操作的静态方法,了解一些常用的方法
Collections
    .emptyList(); // 创建空集合
    .sort(list); // 对集合排序
    .shuffle(list); // 打乱集合顺序
    .unmodifiableList(list); // 设置集合不可变
    .synchronizedList(list); // 变成对应的安全集合
    .synchronizedSet(set);
    .synchronizedMap(map);

关于

1、关于集合的构造函数的初始化参数

public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
}
public Hashtable() {
    this(11, 0.75f);  // default initial capacity (11) and load factor (0.75).
}
  • 初始容量,一般都有默认的静态常量,因此也会有对应的扩容方法
  • 负载因子:一般为0.75,当集合的容量超过自身容量0.75倍时,进行扩容

2、关于 volatile 关键字的理解

  • volatile 能直接访问主内存,因此所有线程可见

  • volatile 禁止了指令重排序,保证了有序性。却不能保证原子性

  • volatile 是JVM提供的最轻量级同步机制

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值