IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java 探究集合List、Map、Set底层的数据结构【钢镚核恒】 -> 正文阅读

[数据结构与算法]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提供的最轻量级同步机制

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:26:57  更:2021-07-22 14:28:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 17:26:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码