Hashtable 和 HashMap 的区别

Java中HashMap和Hashtable的区别 HashMap的迭代器设计为fail-fast是为了快速检测到并发修改,避免在迭代过程中出现数据不一致的问题。当检测到并发修改时,迭代器会立即抛出,提醒开发者需要处理并发问题。 阅读详情

1. 类定义

这个从源码中可以直接看出来,HashMap 继承自 AbstractMap,而 Hashtabl 继承自 Dictionary。

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable

2. 线程安全性

Hashtable 在很多方法定义时都会加上 synchronized 关键字,说明 Hashtabl 是线程安全的,而 HashMap 并不能保证线程安全。

public synchronized int size();
public synchronized boolean isEmpty();
public synchronized boolean contains(Object o);
public synchronized V get(Object key);
public synchronized V put(K key, V value);
...

3. key 和 value 是否允许 null

在 Hashtable 添加元素源码中,我们可以发现,如果添加元素的 value 为 null 时,会抛出 NullPointerException。在程序内部,有这样一行代码 int hash = key.hashCode ,如果添加的 key 为 null 时,此时也会抛出空指针异常,因此,在 Hashtable 中,是不允许 key 和 value 为 null 的。

public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

而在 HashMap 的 put 方法中,调用了 putVal 方法(1.8 版本中),该方法需要有一个 int 类型的 hash 值,这个值是利用内部的 hash 方法产生的。从下面的源代码可以看出,当 key 为 null 时,返回的 hash 值为 0,说明在 HashMap 中是允许 key=null 的情况存在的。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict){
}

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

4. 是否提供 contains 方法

从 HashMap 的 API 可以看出,它只包含 containsKey 和 containsValue 方法。而 Hashtable 还包含了 contains 方法。

HashMap 中把 contains 方法去掉的原因主要它容易引起混淆,不如 containsKey 和 containsValue 表达的准确。

而 Hashtable 中 contains 方法也是调用 containsKey 方法来实现的。

public boolean contains(Object o) {
     return containsKey(o);
}

5. 初始容量

Hashtable 初始容量为 11,默认的负载因子为 0,.75。HashMap 定义了两个常量在对容器进行初始化会用到,可以看到其初始容量为 16,默认的负载因子也是为 0.75.

//---------------------Hashtable-----------------------------
public Hashtable() {
     this(11, 0.75f);
}
public Hashtable(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal Load: "+loadFactor);

    if (initialCapacity==0)
        initialCapacity = 1;
    this.loadFactor = loadFactor;
    // 这里对桶进行初始化
    table = new Entry<?,?>[initialCapacity];
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
//---------------------HashMap-----------------------------
/**
 * The default initial capacity - MUST be a power of two.
 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
 * The load factor used when none specified in constructor.
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

6. 扩容程度

Hashtable 扩容时调用 rehash 方法,增加容器容量的代码在下面。从中可以看出,最终的容量是 newCapacity ,如果该变量在没有大于 MAX_ARRAY_SIZE(静态变量,内部定义为 Integer.MAX_VALUE - 8) 之前,都是按照 oldCapacity*2 + 1 的速度增加的。

int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
    if (oldCapacity == MAX_ARRAY_SIZE)
        // Keep running with MAX_ARRAY_SIZE buckets
        return;
    newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

在 HashMap 中,扩容主要是通过 resize 方法实现的,其扩容的代码是这样的 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];,可见是跟 newCap 变量有关,在正常情况下,newCapa 是按照 oldCap<<1 的速度,即每次长度变为原来的两倍增长的。

 if (oldCap > 0) {
 if (oldCap >= MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return oldTab;
    }
    else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
             oldCap >= DEFAULT_INITIAL_CAPACITY)
        newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
    newCap = oldThr;
else {               // zero initial threshold signifies using defaults
    newCap = DEFAULT_INITIAL_CAPACITY;
    newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}

7. 迭代器

本段话摘自 http://www.cnblogs.com/alexlo/archive/2013/03/14/2959233.html

HashMap 的迭代器(Iterator) 是 fail-fast 迭代器,而 Hashtable 的 enumerator 迭代器不是 fail-fast 的。所以当有其它线程改变了 HashMap 的结构(增加或者移除元素),将会抛出 ConcurrentModificationException,但迭代器本身的 remove() 方法移除元素则不会抛出 ConcurrentModificationException 异常。但这并不是一个一定发生的行为,要看 JVM 。这条同样也是 Enumeration 和 Iterator 的区别。关于 fail-fast 机制可以查看这篇文章。

8. hash 算法

一下下这段分析摘自:https://www.cnblogs.com/xiaoxi/p/7233201.html
hash 算法是将元素定位到相对应桶的位置上,在 Hashtable 中,是这样实现 hash 算法的。因为 Hashtable 中,其桶扩容之后长度为奇数,这种方式的哈希取模会更加均匀(这点还是不清楚为什么)。

int hash = key.hashCode();
// hash 不能超过 Integer.MAX_VALUE,所以要取其最小的 32 个 bit
int index = (hash & 0x7FFFFFFF) % tab.length;

在 JDK 1.8 版本中,HashMap 的 hash 方法如下。

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

final V putValu(int hash,K key,V value,boolean onlyIfAbsent,boolean evict){
    ...
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    ...
} 
  • 其首先是获取该对象的 hashCode 值,然后将 hashCode 值右移 16 位,然后将右移后的值与原来的 hashCode 做 异或 运算,返回结果。
  • 在 putVal 中,通过 (n-1)&hash 获取该对象的键在 hashmap 中的位置。(其中 hash 就是通过 hash 方法获得的值),n 表示 hash 桶数组的长度,并且该长度为 2 的 n 次方。

通常声明 map 集合时不会指定大小,或者初始化的时候就创建一个容量很大的map 对象,所以这个通过容量大小与 key 值进行 hash 的算法在开始的时候只会对低位进行计算,虽然容量的 2 进制高位一开始都是 0,但是 key 的 2 进制高位通常是有值的,因此先在 hash 方法中将 key 的 hashCode 右移 16 位在与自身异或,使得高位也可以参与hash,更大程度上减少了碰撞率。

HashTable和HashMap的区别详解 HashTable和HashMap的区别详解 一、HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。 HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。 HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。 HashMap存数据的过程是 阅读详情

相关推荐

基于反相器的超声波发生和气泡检测电路

本文主要介绍了关于超声波的两种电路——基于反相器的振荡电路和基于逻辑们的气泡检测电路

xehagy的博客 1956

HashMap和Hashtable的区别

HashMap和Hashtable的区别 一、HashMap简介 HashMap是在JDK1.2中引入的Map的实现类。 1.HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。 2. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurren...

xuhuaabc的博客 15万+

工控安全政策系列导读:国际标准IEC 62443标准系列

IEC 62443由ANSI/ISA提出,被ISO/IEC采纳,所以该标准会以不同的名字出现,包括:ANSI/ISA-99,ISA-99,ISA 62443,ISO/IEC 62443,ISO 62443,IEC 62443。其中IEC 62443-2-1已等同采纳为国标,于2016年10月发布,标准编号为GB/T 33007。 IEC 62443是在国...

weixin_34132768的博客 2622

hashmap和hashtable的区别

Map集合转成Set集合--------- Set<Map.Entry<K,V>> entrySet()将key的hashCode和数组容量-1的二进制数进行与操作------得到key的hash值,即数组的下标。获取map集合中所有key-------Set keySet() 所有的键是一个set集合。判断是否包含某个value---------boolean cotainsValue(value)(1)当key通过hash算法得到的哈希值相同时------hash碰撞(hash冲突)

qq_61603498的博客 2332

阿里云人工智能工程师ACA认证免费课程学习笔记

阿里云人工智能工程师ACA认证免费课程学习笔记

engchina的专栏 2013

微信中调起支付宝支付

微信中调用支付宝支付,首先我们知道微信是不能直接调用支付宝的,所以我们需要使用一个中间页提示用户在浏览器中打开,然后进行网页支付或打开app支付。以下为详细唤起支付宝的步骤、业务代码以及相关页面图。 如有问题欢迎评论留言,看到定回复哦^_^\(^o^)/~ 一、微信中唤起支付宝,有几个步骤: 1、中间页引导用户在浏览器中打开去唤起支付宝。 2、浏览器中打开支付宝或app中打开支付宝。 3...

han_calligrapher的博客 2万+

HashMap 和 Hashtable 有什么区别?

HashMap 和 Hashtable 有什么区别? JDK1.8 主要区别如下: 线程安全性不同。HashMap线程不安全;Hashtable 中的方法是Synchronize的。 key、value是否允许null。HashMap的key和value都是可以是null,key只允许一个null;Hashtable的key和value都不可为null。 迭代器不同。HashMap的I...

ConstXiong 1万+

2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛CTF部分WP-哥斯拉流量分析

题目没有任何提示,附件gzl.pcap解题哥斯拉流量300多KB包很多,没啥经验只能挨个看回来之后又狠狠得撸了一把哥斯拉流量分析我这里用的是哥斯拉4.0.1测试链接这里发了两个包,我们进行分析。

深耕网络安全领域,聚焦护网行动(HW)、渗透测试、等级保护(等保)、CTF 竞赛四大核心方向,提供技术干货、实战经验与行业洞察。 1810

ArrayList 和 Vector,HashMap 和 Hashtable的区别

都是Java集合框架中提供的动态数组实现类,它们之间存在一些显著的区别。

chen2017sheng的博客 1104

金蝶云星空核心数据表解析与高效关联查询指南

本文深入解析金蝶云星空核心数据表结构,提供高效关联查询的实战指南。文章详细介绍了基础资料、业务单据和财务模块的关键表及其关联逻辑,重点阐述了如何利用关联表(_LK表)进行跨单据溯源,并分享了编写高性能SQL的实用技巧与避坑建议,帮助开发者、实施顾问和数据分析师快速掌握数据查询方法,提升工作效率。

weixin_29254673的博客 524

基于FPGA的AGC自适应增益控制系统开发

自动增益控制(AGC)是一种在接收信号过程中自动调整放大器增益的技术,以确保输出信号的幅度保持在一个恒定的水平。基于FPGA实现AGC系统具有高性能、低延迟和高度可配置的特点,广泛应用于无线通信、音频处理和雷达等领域。FPGA上的AGC系统提供了一种高效且灵活的方法来处理变化的信号环境。在实际应用中,通过合理的设计和优化,可以显著提高信号处理系统的鲁棒性和可靠性。

走向CTO的路上... 1695

Hashtable和HashMap的区别

下面直接来干货,先说这三个Map的区别: HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化 初始size为11,扩容:newsize = olesize*2+1 计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length HashMap 底层数组+链表实现,可以存储null键和null值,线

yanwendonge的博客 9418

html2canvas - 解决截图后引入的字体样式丢失问题,第三方字体截图导出图片后字体失效,html2canvas截屏生成图片后艺术字体就丢失并且自动转成常规字体了,特殊字体显示不了无法截图怎么办

vue2,vue3,uniapp,html2canvas截图后引入的字体样式丢失,html2canvas艺术字截图不显示,使用外部字体无效,html2canvas无法识别网络字体文件怎么办,ttf文件,网页使用在线字体链接利用html2canvas无法截取,字体样式没有了,font-family第三方字体,@font-face引入本地字体文件后无法被html2canvas识别怎么办,html2canvas文字消失,vue页面正常显示艺术字体但截屏后没有,html2canvas截图存在特殊字体时截图不全,默认

✅ 精选推荐文章 1万+

HashMap和Hashtable区别?

参考: https://blog.youkuaiyun.com/luojishan1/article/details/81952147 存储:HashMap 允许key 和 value 为 null,而 Hashtable 不允许。 线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推...

exodus520的博客 1512

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

HashMap 和 Hashtable 的区别

一、继承的父类不同 HashMap继承自AbstractMap类,而Hashtable继承自Dictionary类。尽管它们实现的接口都是Map接口,但由于继承的父类不同,导致它们在一些行为和方法上存在差异。 二、线程安全性不同 HashMap是非同步的,这意味着它不是线程安全的。在多个线程同时访问HashMap时,如果没有适当的同步机制,可能会导致数据不一致的问题。 Hashtable是线程安全的,它的方法被synchronized修饰,因此在多线程环境下可以直接使用Hashtable而无需额外的同

2301_80140022的博客 1514

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

HashMap和HashTable的区别

HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。不过它们都实现了同时 实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。

sinat_26552841的博客 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java中HashMap和Hashtable有什么区别

原文链接:https://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html Java中HashMap与Hashtable的区别 HashMap和Hashtable都实现了Map接口,但是在决定在Java中是否使用HashMap或Hashtable之前,它们之间有一些重要的区别,这一点很重要。其中一些是线...

Mr.Xie的博客 1万+

HashMap和HashTable区别

文章目录HashMap和HashTable 区别继承对象不同初始化和扩容数据不同线程安全遍历方式不同对于null的不同处理 HashMap和HashTable 区别 继承对象不同 HashMap public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, S...

Hana_one的博客 507

HashMap 和 HashTable 区别

转载:https://www.jianshu.com/p/5c34133ed372 rawer关注 0.12017.01.13 15:15*字数 293阅读 5202评论 1喜欢 3 HashMap 不是线程安全的 HashMap 是 map 接口的实现类,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap 允许 null key 和...

akunshouyoudou的博客 201
上一篇: HashMap源码解析
下一篇: ConcurrentHashMap源码解析
firepation
博客等级 码龄10年 2254粉丝 265原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值