目 录CONTENT

文章目录

HashMap的知识回顾

在水一方
2021-12-17 / 0 评论 / 0 点赞 / 969 阅读 / 3,653 字 / 正在检测是否收录...

项目中Map的使用非常频繁,对于map的知识点的学习回顾是非常有必要的

知识点:

  • HashMap 中的方法在默认情况下是非同步的,这一点和HashTabel对比就可以看出,HashTabel的方法是有synchronized关键词修饰的

  • HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null


    @Test
    public void test(){
        Map<String, Object> map = new HashMap<>();
        map.put(null, null);
        System.out.println(map);
    }

输出结果:{null=null}

往HashMap中存放键值对时,如果key相同,则最新加入的值会覆盖掉原有的值

    @Test
    public void test(){
        Map<String, Object> map = new HashMap<>();
        map.put(null, null);
        map.put(null, "123");
        System.out.println(map);
    }
输出的结果为:{null=123}

ctrl+fn+F12查看文件结构

image.png

HashMap 实现 Iterator,支持 fail-fast

fail-fast是集合世界中错误检测机制,通常出现在集合元素的遍历过程中, java.util包下所有的类都是fail-fast,而concurrent包中的集合都是fail-safe

HashMap如何遍历

方法一: 测试demo

    @Test
    public void test(){
        Map<String, Object> map = new HashMap<>();
        map.put(null, null);
        map.put("name", "123");
        map.put("address", "中国");
        map.put("age", "30");
    for(Map.Entry<String, Object> entry : map.entrySet()){
        System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
    }
    }

输出结果:
key = null, value = null
key = address, value = 中国
key = name, value = 123
key = age, value = 30

For-Each循环是Java5新引入的,所以只能在Java5以上的版本中使用。如果你遍历的map是null的话,For-Each循环会抛出NullPointerException异常,所以在遍历之前你应该判断是否为空引用

方法二:

  • 仅获取key
@Test
    public void getKey(){
        Map<String, Object> map = new HashMap<>();
        map.put(null, null);
        map.put("name", "123");
        map.put("address", "中国");
        map.put("age", "30");
        for (String key : map.keySet()) {
            System.out.println("Key = " + key);
        }
    }

// lambda表达式来写的话就一行代码
 map.forEach((k,v) -> System.out.println(k));

结果:
Key = null
Key = address
Key = name
Key = age

  • 仅获取value
    @Test
    public void getvalue(){
        Map<String, Object> map = new HashMap<>();
        map.put(null, null);
        map.put("name", "123");
        map.put("address", "中国");
        map.put("age", "30");
        for (Object value : map.values()) {
            System.out.println("Value = " + value);
        }

    }

 map.forEach((k,v) -> System.out.println(v));

输出结果:
Value = null
Value = 中国
Value = 123
Value = 30

特点

HashMap中的方法都是异步处理,属于非线程安全

问题

1 为什么HashMap初始容量是2<<4 ?或HashMap的初始容量是多少

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

这个上边注释的意思是,默认初始容量-必须是2的幂

作用:
1.提醒你这个容量就是2的幂,扩容方式也是2的幂。
2.二的幂是使得Key Hash算法后的值尽可能均匀的分布在Map对应的数组位置的合理值

size记录hashMap中KV对的个数

   /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

阈值:

  // TREEIFY_THRESHOLD表示树形阈值
  static final int TREEIFY_THRESHOLD = 8;

在HashMap中存储数据超过8的时候(阈值) 就会由链表转为红黑树(类似于二分查找)

扩容机制

    /**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

HashMap中对于数据的保存个数的扩充是按照倍数来进行的,如果达到了16*0.75个数的时候回进行第一次扩充,而后扩充一倍变为32

hash(Object key)

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

HashMap的原理:

JDK1.8之前

JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 -判断当前元素存放的位置(这里的 n 指的时数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突

JDK1.8

JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。

HashMap中哈希冲突严重时会影响HashMap性能,该如何做

首先要知道什么是哈希冲突,在整个Hash存储过程中,必须要明确两个实际问题,
hashcode()和equal()

Map.Entry和Node<K,V>

参考文章:https://www.hollischuang.com/archives/2091

Java8中遍历Map的常用四种方式

https://mp.weixin.qq.com/s?__biz=MzUyMzcyNjY4Mw==&mid=2247484703&idx=2&sn=1e5aa63f5806f8ebac6f066368b64d09&chksm=fa397f2bcd4ef63df718055f61fc506e0e47a847dbe6b21021815039267522209402abb02c79&scene=21#wechat_redirect

HashTable

HashTable(线程安全)
Hashtable 是遗留类,很多映射的常用功能与 HashMap 类似,不同的是它承自 Dictionary 类,并且是线程安全的,任一时间只有一个线程能写 Hashtable,并发性不如 ConcurrentHashMap,因为 ConcurrentHashMap 引入了分段锁。Hashtable 不建议在新代码中使用,不需要线程安全的场合可以用 HashMap 替换,需要线程安全的场合可以用 ConcurrentHashMap 替换

image.png

待时间充足再更新.....

0

评论区