map接口

本文详细介绍了 Java 中 Map 接口的各种实现类,包括 HashMap、LinkedHashMap 和 TreeMap 的特性与应用场景。深入探讨了 HashMap 的底层实现原理,以及 JDK 8 对其带来的改进。
摘要由CSDN通过智能技术生成

一、Map的实现类的结构:

 |---Map:为双列数据,存储key-value对的数据;
        |---HashMap:作为Map的主要实现类;线程不安全,效率高;key/value可以为null;
            |---LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
                            原因:在原有的HashMap底层结构基础上,添加了一对指针,分别指向前一个和后一个元素。对于频繁的遍历操作,执行效率要高于HashMap。
        |---TreeMap:按照添加的key-value进行排序,实现排序遍历。考虑key的自然排序和定制排序;底层使用红黑树。
        |---HashTable:古老的实现类;线程安全,效率低;key/value不能为null;
            |---Properties:处理配置文件。key/value为String类型。

Map接口继承树:
在这里插入图片描述

2.HashMap底层结构:
jdk7之前使用:数组+链表
jdk8及以后使用:数组+链表+红黑树

二、Map结构的理解:
①Map中的key:无序的、不可重复的,使用Set存储所有key —>key所在的类要重写equals()和hashCode()(以HashMap为例)
② Map中的value:无序的、可重复的,使用Collection存储所有的value —>value所在的类要重写equals()。
③一个键值对:key-value构成了一个Entry对象。
Map中的Entry:无序的、不可重复的,使用Set存储所有的Entry。

三、HashMap的底层实现原理?

1.以jdk7为例说明:

HashMap map = new HashMap();

在实例化以后,底层创建了长度为16的一维数组Entry[] table.
…可能已经执行过多次put…

map.put(key1,value1);
1. 首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算后,得到在Entry数组中的存放位置。
 1.1 如果此位置上数据为空,此时key1-value1添加成功(entry添加成功)  --->1
    1.2 如果此位之上的数据不为空,(意味着此位之上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个/多个数据的哈希值:
        1.2.1 如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功;--->2
        1.2.2 如果key1的哈希值与已经存在的某一个数据(key1-value2)的哈希值相同,继续比较:调用key1所在类的equals(),比较:
            1.2.2.1 如果equals()返回false:此时key1-value1添加成功;--->3
            1.2.2.2 如果equals()返回true:使用value1替换相同key1的value2值。

补充:关于2和3:此时key1-value1和原来的数据以链表的方式存储。在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,默认的扩容方式:扩容为原来容量的2倍,并将原来的数据复制过来。

2.jdk8 相较于 jdk7在底层实现方面的不同:

1.new HashMap():底层没有创建一个长度为16的数组;
2.jdk8 底层的数组是:Node[], jdk7是Entry[];
3.首次调用put()方法时,底层创建长度为16的数组;
4.jdk7底层结构只有:数组+链表。 jdk8中底层结构:数组+链表+红黑树;
4.1形成链表时,jdk7:新的元素指向旧的元素。jdk8,:旧的元素指向新的元素,(七上八下);
4.2当数组的某个索引位置的元素以链表形式存在的数据个数 > 8且当前数组的长度 > 64,此时此索引位置上的所有数据改为使用红黑树存储;
默认的初始化容量:16

四、Map中定义的方法:

增:put(object key, object value)
删:remove(Object key)
改:put(object key, object value)
查:get(object key)
长度:size()
遍历:keySet() / values() / entrySet()

五、HashMap源码中的一些重要常量:
DEFAULT INITIAL CAPACITY : HashMap默认容量,16;
MAXIMUM_ CAPACITY : HashMap最大支持的容量, 2^30;
DEFAULT LOAD_ FACTOR: HashMap默认加载因子;
TREEIFY THRESHOLD: 当Bucket中链表长度大于此默认值,转化为红黑树存储;
UNTREEIFY THRESHOLD: Bucket中红黑树存储的Node小于该默认值,转化为链表存储;
MIN_ TREEIFYCAPACITY:桶中的Node被树化时最小的hash表容量。( 当桶中Node的
数量大到需要变红黑树时,若hash表容量小于MIN_ TREEIFY CAPACITY时,此时应执行resize扩容操作这个MIN TREEIFY_ CAPACITY的值至少是TREEIFY _THRESHOLD的4倍。)
table:存储元素的数组,2的n次幂;
entrySet:存储具体元素的集;
size: HashMap中存储的键值对的数量;
modCount: HashMap扩 容和结构改变的次数;
loadFactor:填充因子;
threshold:扩容的临界值,= 容量*填充因子。

六、HashMap与LinkedHashMap内部存储源码比较:
1.HashMap内部以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;
        }
   }

2.LinkedHashMap继承于HashMap,内部使用Entry存储源码:

 static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值