- 综述:
- 1、HasMap的底层实现原理?
#2、HashMap和Hashtable的异同?
#3、CurrentHashMap与Hashtable的异同? - 1、Map中的key:无序的、不可重复的,使用Set存储所有key;—>key所在的类要重写equals()和hashcode()
#2、Map中的value:无序的,可重复的,使用Collection存储所有的value—>value所在类要重写equals()
#3、一个键值对:key-value构成了一个KeyEntry对象 - 4、键是唯一的,重复会覆盖前一个
#5、HashMap都可以为null,TreeMap键不可以为null,值能为null;Properties,都不能为null; - 映射视图:可以删除,不能添加
- HashMap
- LinkedHashSet、LinkedHashMap
- EnumSet:枚举元素集
- IdentityHashMap:标识散列映射
综述:
Map 接口 键值对的集合 (双列集合)—-(不需要迭代器)
├———Hashtable 接口实现类,同步,线程安全,效率低;不能存储null的key和value
│—————–├Properties:常用来处理配置文件
├———HashMap 接口实现类 ,没有同步,线程不安全,效率高;能存储null的key和value
│—————–├ LinkedHashMap:双向链表和哈希表实现;可以按照输入顺序遍历
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序;考虑按照key进行自然排序或定制排序
└———IdentifyHashMap
面试题:
1、HasMap的底层实现原理?
#2、HashMap和Hashtable的异同?
#3、CurrentHashMap与Hashtable的异同?
Map结构理解:
1、Map中的key:无序的、不可重复的,使用Set存储所有key;—>key所在的类要重写equals()和hashcode()
#2、Map中的value:无序的,可重复的,使用Collection存储所有的value—>value所在类要重写equals()
#3、一个键值对:key-value构成了一个KeyEntry对象
- Map中的EntrySet:无序的,不可重复的,使用Set存储所有的Entry
4、键是唯一的,重复会覆盖前一个
#5、HashMap都可以为null,TreeMap键不可以为null,值能为null;Properties,都不能为null;
检索:
- 必须使用键,get(E key);
- 如果没有设置值,则返回null;或者getOrDefault(key,default;)
- forEach()遍历
更新映射项
counts.put(word,counts.get(word)+1)第一次调用返回null,报空指针异常;counts.put(word,counts.getOrDefault(word)+1)方式一counts.putIfAbsent(word,0);当键以存在时,才放入这个值
counts.put(word,counts.get(word)+1)方式二
counts.merge(word,1.Integer::sum);键原先不存在,方式三
- 如果 key 对应的 value 不存在,则返回该 value 值,如果存在,则返回通过 remappingFunction 重新计算后的值。
映射视图:可以删除,不能添加
- Set
keySet() - Collection
values() - Set
> entrySet()
WeakHashMap:弱散列映射
简介:有一个值,对应的键不再使用;键引用已经消亡,无法删除键/值
使用WeakHashMap,保存键,可以保证垃圾回收机制回收
HashMap
底层实现原理:
- JDK7.0
HashMap map = new HashMap():
在实例化以后,底层创建了长度是16的一维数组Entry[] table。
>>>可能已经执行过多次put<<<
map.put(key1, valuel):
#首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1添加成功.——情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功.—情况2
如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回false:此时key1-value1添加成功。——情况3
如果equals()返回true:使用value1替换value2。
#补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
在不断的添加过程中,会涉及到扩容问题,就认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。
- JDK8.0
new HashMap():底层没有创建一个长度为16的数组
2. jdk8底层的数组是: Node[],而非Entry[]
3,首次调用put()方法时,底层创建长度为16的数组
4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时此索引位置上的所有数据改为使用红黑树存储**。**LinkedHashSet、LinkedHashMap
记住插入的顺序,采取双向链表
- 删除近期少使用的元素,
LinkedHashMap linkedHashMap = new LinkedHashMap(){@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return super.removeEldestEntry(eldest);}};
EnumSet:枚举元素集
- 没有公共构造器,使用静态方法创建
- EnmuMap:键类型的枚举类型映射
IdentityHashMap:标识散列映射
- 内部使用System.identityHashCode方法计算,而不是hashCode
- 使用==判断,而不是equals;可以键不同,值相同
