跟我一起阅读Java源代码之HashMap(二)

上一节中实现的SimpleHashMap,没有解决冲突的问题,这一节我们继续深入

由于table的大小是有限的,而key的集合范围是无限大的,所以寄希望于hashcode散落,肯定会出现多个key散落在同一个数组下标下面,

因此我们要引入另外一个概念,将key和value同时存入table[index]中,即将key和value构成一个对象放在table[index],而且可能存放多个,他们的key对应的index相同,但是key本身不同

现在我们就该讨论以什么样的方式存储这些散落在同一个数组下标的元素

可以考虑数组?

也可以考虑链表存储

源码里面是用链表存储的,其实我也没明白这两种方式在这里有什么区别

,感觉无论在检索和存储上都是差不多的效率,

检索都是需要遍历的方式,而存储也可以是顺序的

那这个问题留给大家吧。

我们来实现链式存储的方式,首先定义一个链表数据结构Entry:

public class Entry<K, V> {
//存储key
final K key;
//存储value
    V value;
//存储指向下一个节点的指针
    Entry<K, V> next;
//存储key映射的hash
final int hash;
}

新的EntryHashMap实现方式

public class EntryHashMap<K, V> {

    transient Entry[] table;

    transient int size;

    public V put(K key, V value) {
        //计算出新的hash
        int hash = hash(key.hashCode());
        //计算出数组小标i
        int i = indexFor(hash, table.length);
        //遍历table[i],如果table[i]没有与新加入的key相等的,则新加入
        //一个value到table[i]中的entry,否则将新的value覆盖旧的value并返回旧的value
        for (Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
        addEntry(hash, key, value, i);
        return null;
    }

    public void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K, V> e = table[bucketIndex];
        //将新的元素插入链表前端
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

    /**
     * 通过hash code 和table的length得到对应的数组下标
     *
     * @param h
     * @param length
     * @return
     */
    static int indexFor(int h, int length) {
        return h & (length - 1);
    }

    /**
     * 通过一定算法计算出新的hash值
     *
     * @param h
     * @return
     */
    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}
时间: 2024-10-16 11:18:31

跟我一起阅读Java源代码之HashMap(二)的相关文章

跟我一起阅读Java源代码之HashMap(一)

最近闲的很,想和大家一起学习并讨论下Java的一些源代码以及其实现的数据结构, 不是什么高水平的东西,有兴趣的随便看看 1. 为什么要用Map,以HashMap为例     很多时候我们有这样的需求,我们需要将数据成键值对的方式存储起来,根据key来获取value(value可以是简单值,也可以是自定义对象)     当然用对象数组也能实现这个目的,查找时可以遍历数组,比较关键字来获取对应的value     从性能上来讲,遍历大数组会消耗性能     从API易用性来讲,需要自己实现查找的逻辑

跟我一起阅读Java源代码之HashMap(三)

上一节我们讲到了如何用散列和链表实现HashMap,其中有一个疑问今天已经有些答案了,为什么要用链表而不是数组 链表的作用有如下两点好处 1. remove操作时效率高,只维护指针的变化即可,无需进行移位操作 2. 重新散列时,原来散落在同一个槽中的元素可能会被散落在不同的地方,对于数组需要进行移位操作,而链表只需维护指针 今天研究下数组长度不够时的处理办法 table为散列数组 1. 首先定义一个不可修改的静态变量存储table的初始大小 DEFAULT_INITIAL_CAPACITY 2.

使用eclipse阅读java源码

很多时候想要阅读java源代码(无论是jdk自带的,还在第三方的),但是我们使用的jar包都是编译好的class包,无法在eclipse中直接打开,此时需要下载源码包. 本文以以下代码为例,HttpClient是apache提供的使用http协议访问网络资源的工具,功能比JDK 的 java.net 包提供的方法更强大.比如我想阅读HttpClient具体封装了哪些方法,都如何实现的呢? HttpClient httpClient = new HttpClient(); 操作步骤如下: 第一步:

java面试之Hashmap

在java面试中hashMap应该说一个必考的题目,而且HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类.虽然 HashMap 和 HashSet 实现的接口规范不同,但它们底层的 Hash 存储机制完全一样,甚至 HashSet 本身就采用 HashMap 来实现的. 通过 HashMap.HashSet 的源代码分析其 Hash 存储机制

全中国的省市县镇乡村数据获取以及展示java源代码

第一步.准备工作(数据源+工具): 数据源(截止目前最全面权威的官方数据):http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/ 爬取数据的工具(爬虫工具):http://jsoup.org/ 第二步.数据源分析: 首先jsoup工具的使用我在这里就不做讲解了,感兴趣的可以自己动手去查阅. 做开发就应该多去了解一些软件工具的使用,在平常开发过程中遇到了才知道从何下手,鼓励大家多平时留意一些身边的软件工具,以备不时之需.在做 这个东西以前,我

java中的HashMap解析

这篇文章准备从源码的角度带大家分析一下java中的hashMap的原理,在了解源码之前,我们先根据自己的理解创建一个hashMap. 先说明一下创建的具体原理是这样的,所谓hashMap,必然是用hash方法来区分不同的key值.学过hash的都知道,我们解决hash冲突的一种方法就是使用散列和桶,首先确定所在的桶号,然后在桶里面逐个查找.其实我们也可以单纯使用数组实现map,使用散列是为了获得更高的查询效率. 要写自己的hashmap前,必须说明一下两个方法,就是hashcode()和equa

Java中关于HashMap的使用和遍历(转)

Java中关于HashMap的使用和遍历 分类: 算法与数据结构2011-10-19 10:53 5345人阅读 评论(0) 收藏 举报 hashmapjavastringobjectiteratorlist 1:使用HashMap的一个简单例子 [java] view plaincopy package com.pb.collection; import java.util.HashMap; import java.util.Iterator; import java.util.Set; im

Java集合:HashMap源码剖析

一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调整大小 5.数据读取                       6.HashMap的性能参数                      7.Fail-Fast机制 一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了不同步和允许使用 null

深入理解Java中的HashMap的实现原理

HashMap继承自抽象类AbstractMap,抽象类AbstractMap实现了Map接口.关系图例如以下所看到的: Java中的Map<key, value>接口同意我们将一个对象作为key.也就是能够用一个对象作为key去查找还有一个对象. 在我们探讨HashMap的实现原理之前,我们先自己实现了一个SimpleMap类,该类继承自AbstractMap类. 详细实现例如以下: import java.util.*; public class SimpleMap<K,V>