`
wojiaolongyinong
  • 浏览: 74078 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

Hashtable和HashMap源码分析

阅读更多

Hashtable和HashMap源码分析

         JDK中自带的Hashtable和HashMap是数据结构中哈希表的实现。除了这两个,还有一个HashSet的实现,但是HashSet基本是基于HashMap实现的,因此在这里我们只讨论Hashtable和HashMap的实现细节。

         首先列出经过源码分析,得出的关于Hashtable和HashMap之间的异同点如下:

         1、Hashtable和HashMap的继承关系比较如下:

 


         其中没有列出它们两个继承的Cloneable和Serializable接口,在下面的分析也是一样,不会分析比较它们的序列化和Cloneable的实现。

 

          2、Hashtable和HashMap之间最为明显的区别:同步处理

                在Hashtable的实现中,所有的外部访问方法都进行了同步化处理,即在方法中添加synchronized关键字;

                Hashtable中的方法示例:

 

Java代码   收藏代码
  1. public synchronized V put(K key, V value) {  
  2.           
  3.      //此处省略内部实现  
  4. }  
  5.   
  6. public synchronized V remove(Object key) {  
  7.            
  8.      //此处省略内部实现  
  9. }  

                而在HashMap的实现中,没有进行同步化处理;

                HashMap中的同样两个方法示例:

 

Java代码   收藏代码
  1. public V put(K key, V value) {  
  2.     //此处省略内部实现  
  3. }  
  4.   
  5. public V remove(Object key) {  
  6.     //此处省略内部实现  
  7. }  

 

 

          3、Hashtable和HashMap关于输入的key和value的限制

          在Hashtable的实现中,不允许添加key或是value为null的键值对,如果key为null,则在put(K key,V value)方法调用hash()方法获取hash值时会抛出空指针异常, 而如果value为null,则在刚进入put(K key, V value)是就会检查而抛出空指针异常,如下具体程序所示:

 

         如下所示为Hashtable中的实现:

 

Java代码   收藏代码
  1. public synchronized V put(K key, V value) {  
  2.         // Make sure the value is not null  
  3.         if (value == null) {//在这里对value值进行了检验,如果为null,则抛出空指针异常  
  4.             throw new NullPointerException();  
  5.         }  
  6.   
  7.         // Makes sure the key is not already in the hashtable.  
  8.         Entry tab[] = table;  
  9.         int hash = hash(key);//在这里调用了下面的hash(Object k)方法  
  10.       
  11.     //在此省略了下面的实现......  
  12. }  
  13.   
  14. //在下面的方法中可以看出,只要传入的k值为null,则在下面调用时就会产生空指针异常  
  15. private int hash(Object k) {  
  16.         if (useAltHashing) {  
  17.             if (k.getClass() == String.class) {  
  18.                 return sun.misc.Hashing.stringHash32((String) k);  
  19.             } else {  
  20.                 int h = hashSeed ^ k.hashCode();  
  21.                 h ^= (h >>> 20) ^ (h >>> 12);  
  22.                 return h ^ (h >>> 7) ^ (h >>> 4);  
  23.              }  
  24.         } else  {  
  25.             return k.hashCode();  
  26.         }  
  27. }  

 

          而在HashMap的实现中,指定索引位置0处用来存放key值为null的键值对,如果在put方法中传入key值为null,如果索引位置0处存在已经存储的元素,则使用现在传进来的value值替换原来的value值,如果没有存储元素,则直接放置。所以我们容易知道,在HashMap中,键值key为null的键值对只能在索引位置为0的地方存储一个,即在整个HashMap中只允许有一个键值对的key为null,后面添加的只是在修改value值。

 

         如下所示为HashMap中的实现:

Java代码   收藏代码
  1. public V put(K key, V value) {  
  2.       if (key == null)  
  3.           return putForNullKey(value);  
  4.     //在这里省略了后面key不为null的实现  
  5. }  
  6.   
  7. //当key为null时调用  
  8. private V putForNullKey(V value) {  
  9.     for (Entry<K,V> e = table[0]; e != null; e = e.next) {  
  10.         //此时索引位置0处不为null,则替换原来的value值  
  11.       if (e.key == null) {  
  12.             V oldValue = e.value;  
  13.             e.value = value;  
  14.             e.recordAccess(this);  
  15.             return oldValue;  
  16.         }  
  17.     }  
  18.     modCount++;  
  19.     //索引位置0处为空,则将键值对放置进去  
  20.     addEntry(0null, value, 0);  
  21.     return null;  
  22. }  

        

        4、在Hashtable和HashMap中,在每一次添加元素时,都会检查此时表中已有的数据个数与临界值的大小关系,当已存入的数据个数大于等于threshold临界值时,Hashtable会调用rehash()方法来对数组进行扩充,HashMap会调用resize(int capacity)方法来对数组进行扩充,然后依次遍历原数组,重新计算元素的hash值,存储到新的数组中,而且两者都是将数组扩大一倍,其中的临界值threshold = loadFactor(装载因子,默认0.75) * capacity(数组大小);

 

         5、在Hashtable和HashMap中都提供了迭代器可让外部调用。在Hashtable和HashMap中均有entrySet()、keySet()、values()方法,分别返回Set<Entry<K,V>>、Set<K>、Collection<V>这三种类型的对象引用,其中就像上面说的,Hashtable返回的对象都是经过同步处理的,举个例子如下:

Java代码   收藏代码
  1. public Set<Map.Entry<K,V>> entrySet() {  
  2.     if (entrySet==null)  
  3.         entrySet = Collections.synchronizedSet(new EntrySet(), this);  
  4.     return entrySet;  
  5. }  

 而在HashMap中返回的对象引用,没有经过同步处理,举例如下:

Java代码   收藏代码
  1. public Set<Map.Entry<K,V>> entrySet() {  
  2.     return entrySet0();  
  3. }  
  4.   
  5. private Set<Map.Entry<K,V>> entrySet0() {  
  6.     Set<Map.Entry<K,V>> es = entrySet;  
  7.     return es != null ? es : (entrySet = new EntrySet());  
  8. }  
3
0
分享到:
评论

相关推荐

    Java集合专题总结:HashMap 和 HashTable 源码学习和面试总结

    Java集合专题总结:HashMap和HashTable源码...本文总结了HashMap和HashTable的源码学习和面试总结,涵盖了它们的存储结构、构造方法、get和put方法的源码分析、Hash表的特点和缺点、HashTable和HashMap的区别等内容。

    HashMap与HashTable的区别(含源码分析)

    5. 源码分析: 查看`HashTable`和`HashMap`的源码,可以发现两者在内部实现上也有所不同。`HashTable`直接使用了数组+链表的方式,而`HashMap`在Java 8及以后版本引入了红黑树优化,当链表长度达到一定阈值(8)时...

    HashMap 源码分析

    在HashMap的源码中,插入、删除和查找操作都是围绕这些数据结构和变量展开的。插入操作会计算键的哈希值,根据哈希值找到对应的数组位置,并可能触发链表或红黑树的插入操作。删除操作同样依据哈希值找到节点,然后...

    HashMap源码分析

    ### HashMap源码分析 #### 一、概述 `HashMap`是Java编程语言中非常重要的一个数据结构,它属于`java.util`包的一部分,是`Map`接口的一个具体实现类。`HashMap`允许存储键值对,并且支持使用`null`作为键或值,这...

    HashMap源码分析系列-第四弹:HashMap多线程解决方案.docx

    #### 二、HashMap线程安全问题分析 在多线程环境中,`HashMap`的主要线程安全问题包括但不限于: 1. **链表死循环问题**:在JDK 1.7中,当多个线程同时进行`put`操作时,可能会出现链表死循环的情况,这是一个严重...

    Java容器之Hashtable源码分析

    - `null`值:`Hashtable`不允许`null`键和`null`值,而`HashMap`允许`null`键但不允许`null`值。 - 构造器默认容量:`Hashtable`默认容量为11,`HashMap`为16。 【总结】 `Hashtable`作为古老的容器,虽然在单线程...

    HashMap资料.zip

    10. **面试常见问题**:面试中常问的问题包括HashMap的扩容机制、哈希冲突解决策略、线程安全性、迭代器的使用等,还可能涉及HashMap的源码分析。 通过深入学习和理解HashMap,不仅可以提高代码的编写效率,也能在...

    并发编程atomic&collections-课上笔记1

    本文主要讲述了 Java 中的并发编程,包括 atomic 包的介绍、CAS 算法的原理、ABA 问题的解决方案,以及 collections 中的 HashMap、HashTable 和 ConcurrentHashMap 的源码分析。 Atomic 包的介绍 ----------------...

    Java集合框架源码剖析:HashSet 和 HashMap

     之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也是说HashSet里面有一个HashMap(适配器模式)。因此本文将重点分析HashMap。  HashMap实现了Map...

    对java基础集合部分(List、HashMap、HashSet、ArrayList等)底层源码的分析与总结

    本文主要探讨了几个关键的集合接口和实现类的底层源码,包括List、HashMap、HashSet等,以及它们的基本操作。 首先,Collection接口是所有单值集合的父接口,提供了增加、删除、遍历元素的基本方法。例如,`add()`...

    深入解读大厂java面试必考点之HashMap全套学习资料

    HashMap是Java编程语言中最常用的集合类之一,尤其在面试中,HashMap的相关知识是考察...这套学习资料应该包含了HashMap的实例分析、源码解读、常见面试题以及实战演练等内容,确保你全面掌握这一核心Java数据结构。

    Java并发系列之ConcurrentHashMap源码分析

    Java并发系列之ConcurrentHashMap源码分析 ConcurrentHashMap是Java中一个高性能的哈希表实现,它解决了HashTable的同步问题,允许多线程同时操作哈希表,从而提高性能。 1. ConcurrentHashMap的成员变量: ...

    java7hashmap源码-to-be-architect:成为Java架构师,你应该学习这些

    hashmap源码 to-be-architect to be a Java architect,you should learn these.This page is updated irregularly. Java基础 深入分析 Java SPI 机制和原理 并发编程专题 Executors线程池 线程池ThreadPoolExecutor...

    全面解析Java中的HashMap类

    本文将深入探讨HashMap的基本特性、哈希表数据结构以及JDK 1.7版本中的HashMap源码分析。 首先,HashMap的基本特性如下: 1. **允许null值**:HashMap允许键和值为null,而Hashtable则不允许。 2. **非线程安全**...

    java8集合源码分析-Outline:大纲

    集合源码分析 JAVA: 基本语法 static 修饰变量 方法 静态块(初始化块 构造函数 ) 静态内部类() 静态导包 final() transient() foreach循环原理() volatile底层实现() equals和hashcode(, ) string,stringbuffer和...

    第二章 ConcurrentHashMap源码分析(JDK8版本)1

    与`HashMap`中的`Node`类似,但`Node`在JDK8中对`value`和`next`字段使用了`volatile`关键字,确保多线程环境下的可见性。`Node`不提供直接修改`value`的方法,而是通过`find`方法辅助`get`操作。 3. **扩容机制** ...

    java技术指南

    《Java技术指南》是一份面向Java程序员的综合技术文档,其涵盖了Java语言从基础到高级的多个方面,旨在帮助Java入门者和进阶者提升技能...文档通过丰富的实例和源码分析,为Java程序员提供了一个全面、深入的学习平台。

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    面试必考之HashMap源码分析与实现.mp4 │ │ │ ├─2.探索JVM底层奥秘ClassLoader源码分析与案例讲解 │ │ 2.探索JVM底层奥秘ClassLoader源码分析与案例讲解.wmv │ │ │ ├─3.锁、分布式锁、无锁实战全局性ID...

Global site tag (gtag.js) - Google Analytics