关闭

【Java基础】深入HashMap

319人阅读 评论(6) 收藏 举报
分类:

       HashMap 是数组+ 链表的组合体,底层结构其实就是一个数组结构,数组中的每一项又是一个链表,当新创建一个HashMap的时候,就初始化一个数组。如下图所示:

      (盗图一张)

                       

HahMap的存取:

        Put: 先根据keyhashcode重新计算hash值,根据hash值得到这个元素在数组中的下标位置,如果这个位置已经存放其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。

<pre name="code" class="java">public V put(K key, V value) {  
    // HashMap允许存放null键和null值。  
    // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。  
    if (key == null)  
        return putForNullKey(value);  
    // 根据key的keyCode重新计算hash值。  
    int hash = hash(key.hashCode());  
    // 搜索指定hash值在对应table中的索引。  
    int i = indexFor(hash, table.length);  
    // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。  
    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;  
            e.recordAccess(this);  
            return oldValue;  
        }  
    }  
    // 如果i索引处的Entry为null,表明此处还没有Entry。  
    modCount++;  
    // 将key、value添加到i索引处。  
    addEntry(hash, key, value, i);  
    return null;  
}  

<pre name="code" class="java">void addEntry(int hash, K key, V value, int bucketIndex) {  
    // 获取指定 bucketIndex 索引处的 Entry   
    Entry<K,V> e = table[bucketIndex];  
    // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry  
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
    // 如果 Map 中的 key-value 对的数量超过了极限  
    if (size++ >= threshold)  
    // 把 table 对象的长度扩充到原来的2倍。  
        resize(2 * table.length);  
} 

        在往HashMap中put元素的时候,首先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

       addEntry(hash, key, value, i)方法根据计算出的hash值,将key-value对放在数组table的i索引处。addEntry 是HashMap 提供的一个包访问权限的方法.

       

       get: 需要根据keyhash值得到对应数组中的位置,就可以知道这个元素是不是我们想要的,而不用去遍历链表,大大优化了查询的效率

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        //先定位到数组元素,再遍历该元素处的链表
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
}
 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }
 
    private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }
       从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。

HashMap如何解决冲突?

    Java中hashMap用链地址法来解决;还有开放地址法,尽可能延长寻址时间.

  

HashMap扩容?

       HashMap 有三个常量: 默认的容器大小是16,最大长度是2的30次方,loadfactor默认是0.75扩充的临界值是16*0.75=12 
       扩充条件:当hashmap中的元素个数超过loadfactor时,就会进行数组扩容,loadfactor的默认值为0.75,也就是说默认情况下,数组大小为16。当hashmap中的元素个数超过16*0.75=12 的时候,就会把数组大小扩展为2*16 = 32,即扩大一倍,然后重新计算每个元素在数组中的位置;

     缺点:在数据量大的情况下,成倍扩容会撑爆CPU.


 ConcurrentHashMap?

       在JDK1.5中,新增加了concurrent并发包,ConcurrentHashMap就是其中的线程安全集合类.它的锁分离技术,大大提高了效率和性能. 每个hash区间使用的锁是ReentrantLock

       在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个 Segment中.

       

       ConcurrentHashMap中对这个数据结构,针对并发稍微做了一点调整。它把区间按照concurrentLevel,分成了若干个segment。默认情况下内部按并发级别为16来创建。对于每个segment的容量,默认情况也是16。concurrentLevel和每个segment的初始容量都是可以通过构造函数设定的。



0
0
查看评论

【Java基础提高】深入分析String(四)

我是小毛驴,一个游戏人,我的梦想是世界和平。转载请注明出处:http://blog.csdn.net/liulongling/article/details/50347279 一、写在前面   本章将深入分析在Java中最常用的String类,主要分析以下几个部分: String...
  • liulongling
  • liulongling
  • 2015-12-17 22:01
  • 4333

《深入体验Java Web开发内幕——核心基础》目录

第1章 XML基础.................................................................................................................. 1... 指点迷津:什么是配置文件1.1 ...
  • zhangxiaoxiang
  • zhangxiaoxiang
  • 2006-05-14 10:20
  • 17715

[Java基础要义] HashMap的设计原理和实现分析

读完本文,你会了解到: 1. HashMap的设计思路和内部结构组成 2. HashMap中的一些概念: 什么是阀值?为什么会有阀值?什么是加载因子?它们有什么作用? 3. HashMap的性能问题以及使用事项 4. HashMap...
  • u010349169
  • u010349169
  • 2014-11-30 14:07
  • 8231

java基础——static深入理解

java中static可以修饰成员变量、方法、类、代码块。 1. static变量 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。两者的区别是: 对于静态变量在内存中只有一个拷贝(节省内存),JVM只...
  • liusong0605
  • liusong0605
  • 2015-10-31 23:03
  • 1192

深入体验Java Web开发内幕-核心基础(看张孝祥的书的笔记一)

 一、XML基础1、XML作为一种通用的数据交换格式,应用越来越广泛。目前许多系统的配置文件都是使用XML格式。配置文件就是记录应用程序的配置信息的文件。比如,某个程序要连接网络上的数据库系统时,需要指定数据库服务器的IP地址、服务器的网络监听端口号、数据库的名称、用户名和密码等信息,这些...
  • jalpha2006
  • jalpha2006
  • 2006-11-01 16:59
  • 1528

Java进阶--深入解析hashmap

HashMap原理先以一个简单的例子来理解hashmap的原理。在Java中先随机产生一个大小为20的数组如下:hash表的大小为7,将上面数组的元素,按mod 7分类如下图:将这些点插入到hashmap中(简单hashmap)后如下图:由上图可知: ① hashmap是用链地址法进行处理,多个k...
  • u013309870
  • u013309870
  • 2017-04-22 22:20
  • 715

如何做到有扎实的Java基础

工作这么多年了,主要用的C语言,对Java语言只停留在看一些代码的层面,或者说是知道一些Java的语法。既然下定了决心学习Android App开发,而且也写了一些App代码, 但是发现对Java一些高级的特性还是比较陌生,比如范型编程,反射等,对Java中的类库也不熟悉,更别提对JVM的理解。 于...
  • rex_nie
  • rex_nie
  • 2016-12-29 00:34
  • 1890

【java集合】HashMap常见面试题

一、HashMap原理1.1 HashMap特性?  HashMap的特性:HashMap存储键值对,实现快速存取数据;允许null键/值;非同步;不保证有序(比如插入的顺序)。实现map接口。1.2 HashMap的原理,内部数据结构?  HashMap是基于hashing的原理,底层使用哈希表(...
  • u012512634
  • u012512634
  • 2017-05-25 18:20
  • 781

Java基础深入解析——类与对象

成员变量与局部变量的区别 1.成员变量定义在类中,整个类中都能够访问。   局部变量定义在局部代码块中,只能在局部代码块中访问。 2.成员变量存在于堆内存中,有初始值。 PS:成员变量分为静态成员变量和非静态成员变量,非静态成员变量存在堆内存中,静态成员变量存在静态方法区中。 静...
  • u010425776
  • u010425776
  • 2015-07-17 21:17
  • 1086

深入Collection之HashMap

深入Collection之HashMap作为Map中最常使用的实现类HashMap,它的重要性当然毋庸置疑,所以这篇文章就是有关HashMap的实现和功能介绍。 成员变量 //默认数组初始化容量 static final int DEFAULT_INITIAL_CAPACITY = 1...
  • paditang
  • paditang
  • 2017-06-05 16:51
  • 413
    个人资料
    • 访问:142092次
    • 积分:5543
    • 等级:
    • 排名:第5692名
    • 原创:94篇
    • 转载:3篇
    • 译文:0篇
    • 评论:2189条
    博客专栏
    最新评论