Java集合-Map

Map学习总结

最近开始复习java基础知识,这篇博客主要是总结一下Map的基本实现类,重点学习关于HashMap的知识。

一、HashMap

HashMap概述:

HashMap基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。

学习HashMap之前,首先需要大概了解一下Hash表是什么
Hash表:
哈希表是种数据结构,它可以提供快速的插入操作和查找操作。不论哈希表中有多少数据,插入和删除(有时包括侧除)只需要接近常量的时间即0(1)的时间级。实际上,这只需要几条机器指令。

  1. 通过关键字确定地址(利用某种规律),存入,若被占用step2.
  2. 根据选择的冲突处理方法,以某种规律计算其它的存储位置,如果选择的一个其它位置仍有冲突,则再选下一个,直到找到没有冲突的位置。

HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出阈值(threshold参数,如下),则要对该哈希表进行 rehash 操作(即重建内部数据结构)。

threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值=“容量*加载因子”,当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。

HashMap数据存储数组:

HashMap就是一个散列表,它是通过“拉链法”解决哈希冲突的:HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。

transient Entry[] table;

table为数组 数组中为Entry实体

 // Entry是单向链表。
 // 它是 “HashMap链式存储法”对应的链表。
 // 它实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数
     static class Entry<K,V> implements Map.Entry<K,V> {
         final K key;
         V value;
         // 指向下一个节点
         Entry<K,V> next;
         final int hash;
 
         // 构造函数。
         // 输入参数包括"哈希值(h)", "键(k)", "值(v)", "下一节点(n)"
         Entry(int h, K k, V v, Entry<K,V> n) {
             value = v;
             next = n;
             key = k;
             hash = h;
        }

         public final K getKey() {
             return key;
         }

         public final V getValue() {
             return value;
         }
 
         public final V setValue(V newValue) {
             V oldValue = value;
             value = newValue;
             return oldValue;
         }

一般情况下,要输出Map中的key 和 value 是先得到key的集合,然后再迭代(循环)由每个key得到每个value
而Entry可以一次性获得这两个值

通过put源码深入理解

public V put(K key, V value) {  
        if (key == null)  
            return putForNullKey(value);
        // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。  
        // 计算二次Hash 
        int hash = hash(key.hashCode());  
        // 通过Hash找数组索引,(n - 1) & hash
        int i = indexFor(hash, table.length);  
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
            Object k;  
       // 若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出!
       if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
                V oldValue = e.value;  
                e.value = value;  
                e.recordAccess(this);  
                return oldValue;  
            }  
        }  
 
        modCount++;  
        addEntry(hash, key, value, i);  
        return null;  
    }  
i的计算方法(n - 1) & hash
  • 一个40亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。
  • 取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;
  • jdk1.8中为:(h = key.hashCode()) ^ (h >>> 16),取模在length不够长的大部分情况下,只有后16位参与,而与前16位异或是为了让前16位参与计算,使得分布的更加均匀

当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就用新value替代旧value,不相同就接在链表尾部或头部 (jdk1.8之后链表长度大于8转化为红黑树)


二、HashMap与Hashtable:

1、HashMap与HashTable的区别:
1) 同步性:Hashtable是同步的,HashMap是异步的,线程不安全
2) 值:HashMap可以让你将空值作为一个表的条目的key或value,但是Hashtable是不能放入空值的。HashMap最多只有一个key值为null,但可以有无数多个value值为null。
2、性能:HashMap的性能最好,HashTable的性能是最差(因为它是同步的)

三、LinkedHashMap:

它的父类是HashMap,使用双向链表来维护键值对的次序,迭代顺序与键值对的插入顺序保持一致。LinkedHashMap需要维护元素的插入顺序,性能略低于HashMap,但在迭代访问元素时有很好的性能,因为它是以链表来维护内部顺序。

四、TreeMap:

Map接口派生了一个SortMap子接口,SortMap的实现类为TreeMap。TreeMap也是基于红黑树对所有的key进行排序,有两种排序 方式:自然排序和定制排序。Treemap的key以TreeSet的形式存储,对key的要求与TreeSet对元素的要求基本一致。

五、WeakHashMap:

WeakHashMap与HashMap的用法基本相同,区别在于:后者的key保留对象的强引用,即只要HashMap对象不被销毁,其对象所有key 所引用的对象不会被垃圾回收,HashMap也不会自动删除这些key所对应的键值对对象。但WeakHashMap的key所引用的对象没有被其他强引 用变量所引用,则这些key所引用的对象可能被回收。WeakHashMap中的每个key对象保存了实际对象的弱引用,当回收了该key所对应的实际对 象后,WeakHashMap会自动删除该key所对应的键值对。

六、IdentityHashMap类:

IdentityHashMap与HashMap基本相似,只是当两个key严格相等时,即key1==key2时,它才认为两个key是相等的 。IdentityHashMap也允许使用null,但不保证键值对之间的顺序。

七、EnumMap类:

1、EnumMap中所有key都必须是单个枚举类的枚举值,创建EnumMap时必须显示或隐式指定它对应的枚举类。
2、EnumMap根据key的自然顺序,即枚举值在枚举类中定义的顺序,来维护键值对的次序。
3、EnumMap不允许使用null作为key值,但value可以。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值