11.剑指JavaOffer-HashMap

经典问题:这三者的区别

image

HashMap的put的逻辑

image

阀值默认8,最低树化容量:64

HashMap 的长度为什么是2的幂次方

Hash 值的范围值-2147483648到2147483647,一个40亿长度的数组,内存是放不下的,用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ (n - 1) & hash”。(n代表数组长度)。这也就解释了 HashMap 的长度为什么是2的幂次方。“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。
length = 16 16 -1 = 15 15二进制 1111 再相与(&)hash效果很好

如何有效减少碰撞

  • 扰动函数:促使元素位置分布均匀,减少碰撞几率(hash函数保证了同时包含高16位和低16位的特性,使得更加的不确定性)

  • 使用final对象,并采用合适的equals()和hashcode(),如String Integer ,因为hashcode不会变

追问,为什么若重写equals(Object obj)方法,就必须重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值?

  • 如果重写了equals(),两个对象判断相等了。但是没有重写hashCode(),有可能两对象相等却hashCode不同,则HashSet这种存唯一值的可能会存了两个一样的对象。

为什么使用HashCode?

  • 通过hashCode比较比equals方法快,当get时先比较hashCode,如果hashCode不同,直接返回false。

hash函数

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

图示:


image.png

1.高16bt不变,低16bit和高16bit做了一个异或(得到的hashcode转化为32位的二进制,前16位和后16位低16bit和高16bit做了一个异或)
2.(n-1)&hash=->得到下标

if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
image

HashMap也可以这样写实现线程安全:

Map safeHashMap = Collections.synchronizedMap(HashMap);

但是和Hashtable一样,都是串行的,效率低下。

concurrentHashMap key和Value不可以为null

image

CAS乐观锁,synchronized悲观锁

image

concurrentHashMap 比java 8之前的 segment(分段加锁),锁更细

  • 首先使用无锁操作CAS插入头节点,失败则循环重试

  • 若头节点已存在,则尝试获取头节点的同步锁,再进行操作

size方法和mappingCount()方法的异同,两者计算是否准确

JDK1.7 和 JDK1.8 对 size 的计算是不一样的。 1.7 中是先不加锁计算三次,如果三次结果不一样在加锁。

JDK1.8 size 是通过对 baseCount 和 counterCell 进行 CAS 计算,最终通过 baseCount 和 遍历 CounterCell 数组得出 size。

JDK 8 推荐使用mappingCount 方法,因为这个方法的返回值是 long 类型,不会因为 size 方法是 int 类型限制最大值。

size()最大值是 Integer 类型的最大值,但是 Map 的 size 可能超过 MAX_VALUE, 所以还有一个方法 mappingCount(),JDK 的建议使用 mappingCount() 而不是size()

原文链接:https://blog.csdn.net/qq_27037443/article/details/94441885

多线程下环境如何进行扩容

HashMap扩容

concurrentHashMap扩容

TreeMap 是有序的散列表,它是通过红黑树实现的。它一般用于单线程中存储有序的映射。(了解一下)

手撕一个Hashmap(无红黑树)

首先,接口类


public interface BtyMap<K,V> {

public V put(K k,V v);

public V get(K k);

  interface Entry<K,V>{

      public K getKey();

      public V getValue();

  }

}

具体实现类:

public class ButyHashMap<K,V> implements BtyMap<K, V>{

    private Entry<K, V>[] arr = null;

    int size;

    public ButyHashMap() {

        arr = new Entry[16];

    }

    public int size() {

        return this.size;

    }

    class Entry<K,V> implements BtyMap.Entry<K, V>{

        private K key;

        private V value;

        private Entry<K, V> next;

        public Entry(){

        }

        public Entry(K key, V value,Entry<K, V> next) {
            this.key = key;
            this.value = value;
            this.next=next;
        }

        @Override
        public K getKey(){return key;}

        @Override
        public V getValue(){return value;}

    }

    @Override
    public V put(K key, V value) {
        V oldValue= null;
        int index = key.hashCode() % arr.length;
        if (arr[index] == null) {
            arr[index] = new Entry<K,V>(key, value,null);
            size++;
        } else {
            Entry<K, V> entry=arr[index];
            Entry<K, V> e = entry;
            while(e != null){
                if(key == e.getKey()||key.equals(e.getValue())){
                    oldValue = e.value;
                    e.value = value;
                    return oldValue;
                }
                e = e.next;
            }
            arr[index] = new Entry(key, value, entry);
            size++;
        }
        return oldValue;
    }

    @Override
    public V get(K key){
        int index=key.hashCode() % arr.length;
        
        if(arr[index]==null)
            return null;
        else{
            Entry<K, V> entry = arr[index];
            while(entry!=null){
                if(key == entry.getKey()||key.equals(entry.getKey())){
                    return entry.value;
                }

                entry=entry.next;
            }
        }
        return null;
    }
}

红黑树规则

红黑树本质上还是二叉查找树,额外的引入了5个约束条件:

1.节点只能是红色或黑色

2.根节点必须是黑色

3.所有NIL节点都是黑色的

4.一条路径上不能出现相邻的两个红色节点

5.在任何递归子树内,根节点到叶子节点的所有路径上包含相同数目的黑色节点

红黑树的插入与旋转
那些年,面试被虐过的红黑树

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容

  • HashMap全方位剖析 常见HashMap面试问答 HashMap是不是有序的? 不是有序的。 有没有有序的Ma...
    从林战士们阅读 863评论 0 5
  • 转自:卓庆森https://www.cnblogs.com/zhuoqingsen/p/8577646.html ...
    Java_xiaoman阅读 6,185评论 0 5
  • 【同读一本书刘姣】 2016-03-002-040 -《谈话的力量》 【正文】 “身体接触是无声地告诉对方:...
    城市格调刘姣阅读 398评论 1 1
  • ”我一直注意着哲学家,阅读了他们的大量文字,此刻我暗自思量,大部分自觉的思维肯定属于本能活动,就连哲学家的思维也是...
    鱼1967阅读 185评论 0 3
  • 从今天起,每天1个RIA便签,坚持100天哦。 由《精进》开始,直面自己逃避已久的写作问题。 当你处于人生中两难抉...
    付晓阅读 247评论 0 3