HashBiMap

BiMap

HashBiMap

    private V put(@Nullable K key, @Nullable V value, boolean force) {
        int keyHash = smearedHash(key);
        int valueHash = smearedHash(value);
        //  key和value完全相同,直接返回
        BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
        if (oldEntryForKey != null
            && valueHash == oldEntryForKey.valueHash
            && Objects.equal(value, oldEntryForKey.value)) {
            return value;
        }
        //  放入值,如果有相同值,force为true时删除旧的从而准备放入新的,否则抛异常
        BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
        if (oldEntryForValue != null) {
            if (force) {
                delete(oldEntryForValue);
            } else {
                throw new IllegalArgumentException("value already present: " + value);
            }
        }
        //  将keey,vakue封装为新的Entry
        BiEntry<K, V> newEntry = new BiEntry<>(key, keyHash, value, valueHash);
        //  若key已存在,删除旧的并插入新的
        //  否则只插入新的
        if (oldEntryForKey != null) {
            delete(oldEntryForKey);
            insert(newEntry, oldEntryForKey);
            oldEntryForKey.prevInKeyInsertionOrder = null;
            oldEntryForKey.nextInKeyInsertionOrder = null;
            return oldEntryForKey.value;
        } else {
            insert(newEntry, null);
            rehashIfNecessary();
            return null;
        }
    }
    //  hashTableKToV:key映射到value的桶,遍历找到entry的尽头
    private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) {
        for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask];
            entry != null;
            entry = entry.nextInKToVBucket) {
            //  遇到了相同的key
            if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) {
                return entry;
            }
        }
        return null;
    }
    //  hashTableKToV:value映射到key的桶
    private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) {
        for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask];
            entry != null;
            entry = entry.nextInVToKBucket) {
            if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) {
            return entry;
            }
        }
        return null;
    }
    //  删除entry方法
    private void delete(HashBiMap.BiEntry<K, V> entry) {
        //  entry在hash桶的位置
        int keyBucket = entry.keyHash & mask;
        HashBiMap.BiEntry<K, V> prevBucketEntry = null;
        //  bucketEntry拿到hash桶的根节点,为链表的根节点,不停向后遍历,直到找到要删除的entry
        for (HashBiMap.BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket];
             true;
             bucketEntry = bucketEntry.nextInKToVBucket) {
            if (bucketEntry == entry) {
                //  prevBucketEntry为null,说明当前节点为链表的头节点,将自己的下一个节点挂到hash桶上即可
                if (prevBucketEntry == null) {
                    hashTableKToV[keyBucket] = entry.nextInKToVBucket;
                } else {
                    //  将链表的前一个entry指向后一个entry,即将entry从链表中删除
                    prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
                }
                break;
            }
            //  未找到,准备下一次遍历,prevBucketEntry为下一次遍历entry的前节点
            prevBucketEntry = bucketEntry;
        }
        //  和删除key大致相同,只是hashTableKToV换成了hashTableVToK
        int valueBucket = entry.valueHash & mask;
        prevBucketEntry = null;
        for (HashBiMap.BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];
             true;
             bucketEntry = bucketEntry.nextInVToKBucket) {
            if (bucketEntry == entry) {
                if (prevBucketEntry == null) {
                    hashTableVToK[valueBucket] = entry.nextInVToKBucket;
                } else {
                    prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
                }
                break;
            }
            prevBucketEntry = bucketEntry;
        }
        //  在大链表上删除entry
        if (entry.prevInKeyInsertionOrder == null) {
            firstInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
        } else {
            entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
        }

        if (entry.nextInKeyInsertionOrder == null) {
            lastInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
        } else {
            entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
        }

        size--;
        modCount++;
    }
    //  添加entry,oldEntryForKey?
    private void insert(HashBiMap.BiEntry<K, V> entry, @Nullable HashBiMap.BiEntry<K, V> oldEntryForKey) {
        int keyBucket = entry.keyHash & mask;
        //  将entry放在hash桶对应位置所保存链表的头部
        entry.nextInKToVBucket = hashTableKToV[keyBucket];
        hashTableKToV[keyBucket] = entry;

        int valueBucket = entry.valueHash & mask;
        entry.nextInVToKBucket = hashTableVToK[valueBucket];
        hashTableVToK[valueBucket] = entry;

        if (oldEntryForKey == null) {
            //  当前entry为新添加的entry,将其放在大链表的尾部
            entry.prevInKeyInsertionOrder = lastInKeyInsertionOrder;
            entry.nextInKeyInsertionOrder = null;
            //  如果当前元素为第一个元素,那么大链表头节点持有引用,
            //  否则前一个结点指向该节点
            if (lastInKeyInsertionOrder == null) {
                firstInKeyInsertionOrder = entry;
            } else {
                lastInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
            }
            lastInKeyInsertionOrder = entry;
        } else {
            //  当前节点替换旧节点(修改原节点的值
            entry.prevInKeyInsertionOrder = oldEntryForKey.prevInKeyInsertionOrder;
            //  若老节点为大链表的第一个节点则大链表头节点指向当前节点
            //  否则前节点改为指向当前节点
            if (entry.prevInKeyInsertionOrder == null) {
                firstInKeyInsertionOrder = entry;
            } else {
                entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
            }
            //  将下一个节点由oldEntryForKey重指向到entry
            entry.nextInKeyInsertionOrder = oldEntryForKey.nextInKeyInsertionOrder;
            if (entry.nextInKeyInsertionOrder == null) {
                lastInKeyInsertionOrder = entry;
            } else {
                entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry;
            }
        }

        size++;
        modCount++;
    }

    private void rehashIfNecessary() {
        HashBiMap.BiEntry<K, V>[] oldKToV = hashTableKToV;
        if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
            int newTableSize = oldKToV.length * 2;

            this.hashTableKToV = createTable(newTableSize);
            this.hashTableVToK = createTable(newTableSize);
            this.mask = newTableSize - 1;
            this.size = 0;

            for (HashBiMap.BiEntry<K, V> entry = firstInKeyInsertionOrder;
                 entry != null;
                 entry = entry.nextInKeyInsertionOrder) {
                insert(entry, entry);
            }
            this.modCount++;
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Immutable Collections 这才是真正的不可修改的集合 2. Multiset: 看看如何把...
    183207efd207阅读 598评论 0 1
  • 目前Google Guava在实际应用中非常广泛,本篇博客将以博主对Guava使用的认识以及在项目中的经验来给大家...
    spark孙阅读 2,640评论 0 5
  • 目前Google Guava在实际应用中非常广泛,本篇博客将以博主对Guava使用的认识以及在项目中的经验来给大家...
    java高并发阅读 1,672评论 0 8
  • 目前Google Guava在实际应用中非常广泛,本篇博客将以博主对Guava使用的认识以及在项目中的经验来给大家...
    张丰哲阅读 15,412评论 12 184
  • maven配置HTTP代理 基于安全考虑,公司中可能要求通过安全认证的代理访问英特网,这就需要为Maven配置HT...
    哈哈大圣阅读 554评论 0 0