(Java学习笔记)JavaSE 集合 Map接口(附:HashMap底层实现原理)

Map接口

存储双列数据,保存具有映射关系“key-value对”的集合 -->数学函数 y = f(x)

1、Map接口概述

  • Map中的key是无序的、不可重复的,使用Set结构去存储 (相当于函数里的自变量x)

​ —>要求在存储时,key所在的类要重写equals()和hashCode() (以HashMap为例、TreeMap不需要)

  • Map中的value是无序的、可重复的,使用Collection结构去存储 (相当于函数里的因变量y)

​ —>要求在存储时,value所在的类要重写equals()

  • 一个键值对 key-value对,构成了一个Entry对象,Entry是无序的、不可重复的,使用Set结构去存储

2、Map接口常用方法

  1. 添加、删除、修改操作:
    • Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
    • void putAll(Map m):将m中的所有key-value对存放到当前map中
    • Object remove(Object key):移除指定key的key-value对,并返回value
    • void clear():清空当前map中的所有数据
  2. 元素查询的操作:
    • Object get(Object key):获取指定key对应的value
    • boolean containsKey(Object key):是否包含指定的key
    • boolean containsValue(Object value):是否包含指定的value
    • int size():返回map中key-value对的个数
    • boolean isEmpty():判断当前map是否为空
    • boolean equals(Object obj):判断当前map和参数对象obj是否相等
  3. 元视图操作的方法: 遍历
    • Set keySet():返回所有key构成的Set集合
    • Collection values():返回所有value构成的Collection集合
    • Set entrySet():返回所有key-value对构成的Set集合
    @Test
    public void test3(){
        HashMap hashMap = new HashMap();
        hashMap.put("aa",123);
        hashMap.put(789,'f');
        hashMap.put("dd",45);
        hashMap.put(false,"kk");
        //Set keySet():返回所有key构成的Set集合
        Set set = hashMap.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //Collection values():返回所有value构成的Collection集合
        Collection values = hashMap.values();
        for (Object obj : values){
            System.out.println(obj);
        }
        //Set entrySet():返回所有key-value对构成的Set集合
        Set entrySet = hashMap.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }      
    }

3、HashMap

主要实现类 ,线程不安全,效率高,可以存储 值为null 的key和value

  • HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true, hashCode 值也相等。

  • HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。

  • 底层:数组 + 链表 (jdk 7及以前)

    ​ 数组 + 链表 + 红黑树 (jdk 8)

3.1、底层实现原理:(jdk7)

@Test
    public void test1(){
        //实例化后,底层创建了一个长度为16的Entry[] table
        HashMap hashMap = new HashMap();

        //添加元素(不一定为第一次):首先调用key1 所在类的hashCode(),计算key1的哈希值,此哈希值经过某种算法计算后,
        // 得到在table[] 中的存放位置,若此位置上的数据为空,此时的key1-value1(table[1])添加成功。----情况1
        // 若此位置上的数据不为空,(意味着此位置上存在着一个或多个数据(以链表形式存在)),比较key1与已经存在的数据的hash值,
        // 若key1的哈希值与已经存在的数据的hash值都不相同,此时key1-value1(table[1])添加成功。  ----情况2
        // 若key1的哈希值与已经存在的某一个数据(key2-value2)的hash值相同,继续比较:(调用key1所在类的equals(key2)),
        // 若equals()返回false,此时的key1-value1(table[1])添加成功。  ----情况3
        // 若 equals()返回true,则会让value1去替换相同key的value值。

        //补充:关于情况2、3:此时key1-value1和原来的数据以链表的形式存储
        //在不断地添加过程中,Entry[] table会不断地扩容:默认的扩容方式:扩容为原来长度的二倍,并将原有的数据复制过来
        
        //注:扩容 :在已经添加的元素将超出临界值(且要存放的位置非空)时,添加新个元素时,扩容)
        //初始化临界值12 = 16:默认初始容量 * 0.75:加载因子
        hashMap.put("key1", "Value1");
        
    }

在形成链表结构时,新添加的key-value对在链表的头部(七上八下)

3.2、底层实现原理:(jdk8)

   @Test
    public void test2(){
        //实例化  底层没有创建长度为16的数组
        HashMap hashMap = new HashMap();
        
        //首次调用put()时,底层创建了一个长度为16的数组Node[] table
        hashMap.put("key1", "Value1");
        
        //持续添加数据,当数组中的一个索引位置以链表形式存在的数据个数 >8且当前数组长度 >64时,
        // 此时此索引位置上的所有数据改为使用红黑树存储
        //目的:当比较该元素与索引位置上的所有元素的hash值时,采用二叉树查找,提高查找效率
        
        //扩容机制与jdk7相同

    }

在形成链表结构时,新添加的key-value对在链表的尾部(七上八下)

3.3、HashMap源码中的重要常量

  • AL_CAPACITY : HashMap的默认容量,16
  • MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30
  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树
  • UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的 数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行 resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4 倍。)
  • table:存储元素的数组,总是2的n次幂
  • entrySet:存储具体元素的集
  • size:HashMap中存储的键值对的数量
  • modCount:HashMap扩容和结构改变的次数。
  • threshold:扩容的临界值,=容量*填充因子
  • loadFactor:填充因子

4、LinkedHashMap

  • 底层结构与LinkegHashSet相似,可以保证在遍历Map元素时,以添加的顺序进行遍历。

不同在于,LinkedHashMap存储的元素为“key-value对”,LinkegHashSet存储的元素为无序的、不可重复的

  • LinkedHashMap在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序

  • LinkedHashMap中的内部类:Entry (HashMap中的内部类:Node)

5、TreeMap

保证按照添加的key-value对进行排序,实现排序遍历。(按照key 进行自然排序或定制排序)底层使用的是红黑树

向TreeMap中添加key-value,要求key必须是由同一个类创建的对象(要求key类型相同)。

6、Properties

  • Properties 类是 Hashtable 的子类,该对象用于处理属性文件
  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
  • 存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");//加载流对应的文件:jdbc.properties
System.out.println(user);

注:本文章是根据哔哩哔哩公开课 Java -Java 学习- Java 基础到高级-宋红康-零基础自学Java-尚硅谷 整理所得
大爱康师傅!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值