• Java集合 —— Map集合


    1、 Map接口和Collection接口的不同:

    • 它们两个不存在继承关系,都是属于java.util包下面的平级关系
    • Map集合存储的元素都是成对出现的,Map元素的键是唯一的,值是可以重复。把这样的元素理解为:夫妻对
    • Collection集合存储的元素都是单独出现的,Collection接口下面的Set是元素唯一的, List集合中元素是可以重复的。
      这样的单独出现的元素,可以理解为单身

    2、 Map集合的特点:

    • 将键映射到值的对象、
    • key和value可以是任意的引用类型的数据
    • 一个映射不能包含重复的键(map集合的key值不能重复)
    • 每个键最多可以映射到一个值(每个键值对只有一个key值,一个value值)
    • 同样的值可以对应多个不同的键(不同的键值对可以拥有相同的value值)

    3、 Map集合的功能:

    1、添加功能: put(K key,V value)将指定的值与该映射中的指定键相关联

    2、删除功能:
    remove(Object key)如果存在,从该map集合中删除一个键的映射
    void clear()从该map集合中删除所有的映射

    3、长度功能:int size()返回此地图中键值映射的数量

    4、HashMap原理

    谈谈你对HashMap的理解?

    先从底层数据出发。HashMap实现Map接口,存储键值对。JDK8版本底层结构基于数组+链表/红黑树,当每个桶中元素达到树化阈值8,并且数组总量大于64,由链表转为红黑树;元素小于阈值6,转回链表。针对JDK7版本做了优化,将最坏查询由O(n)降到O(logn)。

    其次,HashMap线程不安全。

    HashMap的数据插入原理是怎样的?

    在这里插入图片描述

    点击连接 HashMap面试题大全,兄弟姐妹们背起来

    5、HashTable特点

    HashTable的继承树如下图:
    在这里插入图片描述
    (1)底层使用Entry数组保存元素

    (2)默认初始容量是11,加载因子是0.75。

        /**
         * Constructs a new, empty hashtable with a default initial capacity (11)
         * and load factor (0.75).
         */
        public Hashtable() {
            this(11, 0.75f);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (3)可以指定初始容量和加载因子。指定初始容量时即按照指定值进行容量分配。

    	public Hashtable(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new IllegalArgumentException("Illegal Load: "+loadFactor);
    
            if (initialCapacity==0)
                initialCapacity = 1;
            this.loadFactor = loadFactor;
            table = new Entry<?,?>[initialCapacity];
            threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        }
        
        public Hashtable(int initialCapacity) {
            this(initialCapacity, 0.75f);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    (4)线程安全,方法使用synchronized修饰。

    (5)具有fail-fast的特征

    (6)key和value均不允许为null,否则抛出java.lang.NullPointerException异常。

    (7)计算索引的方式为:
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;

    (8)如果key已经存在,则新value覆盖旧value,并返回旧value

    public synchronized V put(K key, V value) {
            // Make sure the value is not null
            if (value == null) {
                throw new NullPointerException();
            }
    
            // Makes sure the key is not already in the hashtable.
            Entry<?,?> tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            @SuppressWarnings("unchecked")
            Entry<K,V> entry = (Entry<K,V>)tab[index];
            for(; entry != null ; entry = entry.next) {
                if ((entry.hash == hash) && entry.key.equals(key)) {
                    V old = entry.value;
                    entry.value = value;
                    return old;
                }
            }
    
            addEntry(hash, key, value, index);
            return null;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (9)如果超过扩容阈值threshold(数组容量 * 加载因子),则进行rehash扩容。新数组容量=(原数组容量 << 1) + 1

    6、LinkedHashMap

    扩展HashMap增加双向链表的实现,号称是最占内存的数据结构。支持iterator()时按Entry的插入顺序来排序(但是更新不算, 如果设置accessOrder属性为true,则所有读写访问都算)。

    实现上是在Entry上再增加属性before/after指针,插入时把自己加到Header Entry的前面去。如果所有读写访问都要排序,还要把前后Entry的before/after拼接起来以在链表中删除掉自己。

    7、TreeMap

    以红黑树实现,篇幅所限详见入门教程。支持iterator()时按Key值排序,可按实现了Comparable接口的Key的升序排序,或由传入的Comparator控制。可想象的,在树上插入/删除元素的代价一定比HashMap的大。

    支持SortedMap接口,如firstKey(),lastKey()取得最大最小的key,或sub(fromKey, toKey), tailMap(fromKey)剪取Map的某一段。

    8、ConcurrentHashMap

    并发优化的HashMap,默认16把写锁(可以设置更多),有效分散了阻塞的概率,而且没有读锁。

    数据结构为Segment[],Segment里面才是哈希桶数组,每个Segment一把锁。Key先算出它在哪个Segment里,再算出它在哪个哈希桶里。

    支持ConcurrentMap接口,如putIfAbsent(key,value)与相反的replace(key,value)与以及实现CAS的replace(key, oldValue, newValue)。

    没有读锁是因为put/remove动作是个原子动作(比如put是一个对数组元素/Entry 指针的赋值操作),读操作不会看到一个更新动作的中间状态。

    9、ConcurrentSkipListMap

    JDK6新增的并发优化的SortedMap,以SkipList实现。SkipList是红黑树的一种简化替代方案,是个流行的有序集合算法,篇幅所限见入门教程。Concurrent包选用它是因为它支持基于CAS的无锁算法,而红黑树则没有好的无锁算法。
    很特殊的,它的size()不能随便调,会遍历来统计。

  • 相关阅读:
    约数——正约数个数求法及其原理,求N的正约数集合
    攻防世界WEB练习-easyupload
    BUUCTF misc 专题(121)[watevrCTF 2019]Evil Cuteness
    【Qt-23】基于QCharts绘制曲线图
    【操作系统】进程:哲学家进餐问题
    基于C++实现银行业务系统
    linux手动安装scapy2.5
    STM32学习笔记:驱动SPI外设读写FLASH
    网络工程师必备神器---千月网络助手(附下载链接)
    VMware16虚拟机安装及配置(保姆级教程),这一篇就够了
  • 原文地址:https://blog.csdn.net/Champion_me/article/details/125515071