概述
HashMap作为一个使用频率非常高的key-value容器,在我们的项目中经常用到,而且,面试官也很喜欢问。这就要求我们不能只停留在使用层面,对于它底层的实现也需要弄明白。本文主要是针对jdk1.8中的HashMap使用层面的一个讲解,尤其是jdk1.8中新增了一些api,你都了解吗?
HashMap介绍
HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现,它是一个key-value结构的容器。
- 是一个key-value的映射容器,key不重复
- jdk8中的HashMap基于数组+链表+红黑树实现
- 不保证键值的顺序
- 可以存入null值
- 非线程安全,多线程环境下可能存在问题
以上是HashMap的类结构图:
- 继承了AbstractMap,实现了Map接口,提供了key,value结构格式访问的方法
- 实现了Cloneable接口,表示HashMap支持clone
- 实现了Serializable接口,表示HashMap支持序列化
构造方法
方法 | 说明 |
HashMap() | 构造一个默认负载因子为0.75的HashMap |
HashMap(int initialCapacity, float loadFactor) | 构造一个自定义初始容量和负载因子的HashMap |
HashMap(Map<? extends K, ? extends V> m) | 构造一个内容为m的HashMap |
这里的负载因子和初始容量涉及到扩容机制,后面会重点提到。
关键方法
方法 | 说明 | jdk8新增 |
V put(K key, V value) | 添加key value,会覆盖相同key上的内容 | |
V putIfAbsent(K key, V value) | 添加key value,只有key不存在才会添加value | 是 |
putAll(Map<? extends K, ? extends V> m) | 将另外一个map中的元素添加进来 | |
V remove(Object key) | 根据key删除,返回删除关联的value | |
boolean remove(Object key, Object value) | 只有key,value都匹配才会删除 | 是 |
void clear() | 清空map内容 | |
V get(Object key) | 根据key获取value | |
V getOrDefault(Object key, V defaultValue) | 根据key获取value,如果返回null,使用默认值 | 是 |
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) | 根据function自定义替换逻辑 | 是 |
replace(K key, V oldValue, V newValue) | 根据key, oldvalue替换为newValue | 是 |
V replace(K key, V value) | 替换map中key中的值为value, 前提key在map中存在 | 是 |
V compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) | 对 map 中指定 key 的值进行重新计算,如果计算出新的值是null, 会删除这个key | 是 |
V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction) | 对map中不存在的key进行重新计算获取新的value, put到map中 | 是 |
V computeIfPresent(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) | 对map中存在的key进行重新计算获取新的value, put到map中,如果新的value是空的话,则删除这个key | 是 |
V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction) | 合并map中key下的value和传入的newValue,合并逻辑通过函数式变成定义,如果返回为null,则删除map中的key | 是 |
Entry是HashMap中节点实现的接口,y用于遍历,它也新加了一些新的api。
方法 | 说明 | jdk8新增 |
K getKey() | 获取这个节点的key | |
V getValue() | 获取这个节点的value | |
V setValue(V value) | 设置这个节点的value | |
V remove(Object key) | 根据key删除,返回删除关联的value | |
comparingByKey() | 静态方法,获取key的排序比较器,如果map中key包含null, 空指针 | 是 |
comparingByValue() | 静态方法,获取value的排序比较器,如果map中value包含null, 空指针 | 是 |
comparingByKey(Comparator<? super K> cmp) | 静态方法,自定义key的排序比较器,如果map中key包含null, 空指针 | 是 |
comparingByValue(Comparator<? super V> cmp) | 静态方法,自定义value的排序比较器,如果map中value包含null, 空指针 | 是 |
使用案例
- map的增删查基本操作
@Test public void test1() { Map<String, Integer> map = new HashMap(); map.put("cxw", 1); map.put("yms", 2); // 会覆盖前面的key yms map.put("cxw", 5); System.out.println(map); // {cxw=5, yms=2} // 不存在cxw 这个key,才会覆盖 map.putIfAbsent("cxw", 8); map.putIfAbsent("cc", 1); System.out.println(map); // {cc=1, cxw=5, yms=2} Integer cxwInt = map.get("cxw"); System.out.println(cxwInt); // 5 // 不存在key,使用默认值 Integer defaultGet = map.getOrDefault("kk", 0); // 0 // 根据key删除 map.remove("cc"); // 根据key value删除, key, value都等值才会删除成功,所以这里删除不成功 map.remove("cxw", 10); System.out.println(map); }
运行结果:
- compute相关操作
@Test public void test2() { Map<String, Integer> map = new HashMap(); map.put("cxw", 1); map.put("yms", 2); map.put("kk", 2); // 计算 map.compute("cxw", new BiFunction<String, Integer, Integer>() { @Override public Integer apply(String key, Integer integer) { return 100; } }); System.out.println(map); //{kk=2, cxw=100, yms=2} map.compute("cxw", new BiFunction<String, Integer, Integer>() { @Override public Integer apply(String key, Integer integer) { // 返回null,会删除cxw这个key return null; } }); System.out.println(map); //{kk=2, yms=2} // 只有key不存在才会进行操作, yms存在,所以保持不变 map.computeIfAbsent("yms", new Function<String, Integer>() { @Override public Integer apply(String s) { return 10; } }); System.out.println(map); //{kk=2, yms=2} // 只有key存在才会进行操作, yms存在,所以发生变化 map.computeIfPresent("yms", new BiFunction<String, Integer, Integer>() { @Override public Integer apply(String s, Integer integer) { return 10; } }); System.out.println(map); //{kk=2, yms=10} }
运行结果:
- 测试HashMap节点的comparing相关方法
@Test public void test3() { Map<String, Integer> map = new HashMap(); map.put("cxw", 1); map.put("yms", 2); map.put("kk", 2); // 根据key排序 List<Map.Entry<String, Integer>> entrys = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect( Collectors.toList() ); entrys.forEach(item -> { System.out.println(item.getKey()); }); }
运行结果:
总结
本文主要讲解了HashMap的重要特性以及重点API,特别是jdk8中新引入了一些方法,可能你都不知道,但的确有用。