HashTable和HashMap的区别

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

散列表

概念:Hash table,也叫哈希表,是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
HashMap/HashTable内部用Entry数组实现哈希表,而对于映射到同一个哈希桶(数组的同一个位置)的键值对,使用Entry链表来存储(解决hash冲突)。
在这里插入图片描述

Java中HashTable和HashMap(JDK8以前)的差异

HashTable自JDK1.0起就开始出现至今,而HashMap直到JDK1.2才出现。HashMap出现后,完善了HashTable过去的不足,但也来了新的不足之处。

相同点:
a.内部Entry

HashTable和HashMap里面有一个内部类Entry,用来存放真正的Key-Value键值对;

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;

        /**
         * Creates new entry.
         * 内部Entry类结构,存放真正的Key-Value键值对
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }
        .......
  }
b.默认负载因子

默认负载因子都为0.75
HashTable:

//指定初始容量大小的构造函数
public Hashtable(int initialCapacity) {
	this(initialCapacity, 0.75f);
}

HashMap:

/**
 * The load factor used when none specified in constructor.
 * 负载因子
 */
  static final float DEFAULT_LOAD_FACTOR = 0.75f;
不同点:
a.继承的类不同:

HashTable继承和实现:

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

HashMap继承和实现:

public class HashMap<K,V> extends AbstractMap<K,V>
   		implements Map<K,V>, Cloneable, Serializable
b.默认初始大小

HashTable中默认构造大小为11,负载因子为0.75f;

//默认无参构造函数
public Hashtable() {
    this(11, 0.75f);
}

HashMap中的初始大小为16(1 << 4 ),负载因子也是0.75f;

//默认无参构造函数
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
public HashMap() {
    this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
c.两者的Hash函数不同

HashTable会尽量使用素数、奇数,哈希表的大小为素数时,简单的取模哈希的结果会更加均匀。代码中使用hashSeed值与对象的哈希值做异或运算得出所需存储的对象的哈希值。

/**
* 与此实例关联的随机值,使哈希冲突更难找到的密钥哈希码。
*/
transient int hashSeed;
private int hash(Object k) {
    // hashSeed will be zero if alternative hashing is disabled.
    return hashSeed ^ k.hashCode();
}

HashMap总是使用2的幂作为哈希表的大小,为了减小哈希冲突,在HashSeed与对象哈希值做异或运算之后,再做两次无符号右移位运算和异或运算,得出的哈希值。

//hashMap中给定的Hash算法
final int hash(Object k) {
    int h = hashSeed;
 	h ^= k.hashCode();
	h ^= (h >>> 20) ^ (h >>> 12);
	return h ^ (h >>> 7) ^ (h >>> 4);
}

HashMap和HashTable在计算hash时都用到了一个叫hashSeed的变量。这是因为映射到同一个hash桶内的Entry对象,是以链表的形式存在的,而链表的查询效率比较低,所以HashMap/HashTable的效率对哈希冲突非常敏感,所以可以额外开启一个可选hash(hashSeed),从而减少哈希冲突。

d.允许的最大容量

HashTable中最大容量为:2147483647 [0x7fffffff] - 8

//最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

HashMap中最大容量则为:1073741824

//最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
e.针对触发扩容的时机不同

前面有说到,在两者在默认构造的时候,都有一个默认的负载因子值为0.75f。通过该负载因子计算得出阈值(threshold),这个阈值就是作为扩容的触发点。
HashTable在触发扩容操作时,是当前哈希表中的Entry总数>=阈值(threshold)时。

//HashTable
//如果容器中的元素数量已经达到阀值,则进行扩容操作  
if (count >= threshold) {
	// Rehash the table if the threshold is exceeded
	rehash();
	
	tab = table;
	hash = hash(key);
	index = (hash & 0x7FFFFFFF) % tab.length;
}

protected void rehash() {
	.......
	int newCapacity = (oldCapacity << 1) + 1;//原容量的2倍+1
	.......
  	Entry<K,V>[] newMap = new Entry[newCapacity];
  	.......   
    for (int i = oldCapacity ; i-- > 0 ;) {
        for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
            Entry<K,V> e = old;
            old = old.next;
            
            if (rehash) {
                e.hash = hash(e.key);
            }
            //& 0x7FFFFFFF目的为了去掉符号;% newCapacity减少hash冲突
            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
            e.next = newMap[index];
            newMap[index] = e;
        }
    }
}

而HashMap触发扩容操作时,要同时判断阈值和哈希冲突,当两者同时满足时,才进行原基础的2倍扩容

//HashMap
//如果容器中的元素数量已经达到阀值且哈希桶不为空 
if ((size >= threshold) && (null != table[bucketIndex])) {
	// 每次扩充为原来的2n 
	resize(2 * table.length);
	hash = (null != key) ? hash(key) : 0;
	bucketIndex = indexFor(hash, table.length);
}
///获取桶索引
static int indexFor(int h, int length) {
	// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
	return h & (length-1);
}
f.允许空值的情况

HashMap是支持null键和null值的,而HashTable在遇到null时,会抛出NullPointerException异常。这并不是因为HashTable有什么特殊的实现层面的原因导致不能支持null键和null值,这仅仅是因为HashMap在实现时对null做了特殊处理,将null的hashCode值定为了0,从而将其存放在哈希表的第0个bucket中。

//HashTable中put操作
public synchronized V put(K key, V value) {
	//确保value不能为空判断
	if (value == null) {
	    throw new NullPointerException();
	}
        ......
}

HashMap在实现时对null做了特殊处理

//HashMap中put操作
public V put(K key, V value) {
    ......
    if (key == null)
        return putForNullKey(value);
    ......
    }
}
/**
     * Offloaded version of put for null keys
     */
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;
}
h.线程安全

HashTable是线程安全的,HashMap不是线程安全的。
HashTable:在操作方法前,用synchronized修饰,保证线程的安全性,但效率极低。

//put操作
public synchronized V put(K key, V value);
//remove操作
public synchronized V remove(Object key);
//get操作
public synchronized V get(Object key);
//clear操作
public synchronized void clear() ;
......

HashMap:在以上操作中没有synchronized关键字修饰,并且它的设计就不是以线程安全来设计的。它线程不安全的地方,主要在于扩容后,旧的Entry在关联新的哈希桶时会出现线程不安全的情况。

HashMap和HashTable的总结

HashTable已经被淘汰了,简单来说就是,如果你不需要线程安全,那么使用HashMap,如果需要线程安全,那么使用ConcurrentHashMap。HashTable已经被淘汰了,不要在新的代码中再使用它。

虽然HashMap和HashTable的公开接口应该不会改变,或者说改变不频繁。但每一版本的JDK,都会对HashMap和HashTable的内部实现做优化,比如JDK 1.8的红黑树优化。所以,尽可能的使用新版本的JDK吧,除了那些炫酷的新功能,普通的API也会有性能上有提升。

为什么HashTable已经淘汰了,还要优化它?因为有老的代码还在使用它,所以优化了它之后,这些老的代码也能获得性能提升。

版权声明:Echo_IX https://blog.youkuaiyun.com/chenxiaoti/article/details/82900630

CS算法实战:用MATLAB从零实现SAR点目标成像(附完整代码) 本文详细介绍了如何使用MATLAB从零实现SAR点目标CS成像算法,涵盖Chirp Scaling(CS)算法的核心理论、距离徙动校正(RCMC)和方位压缩等关键步骤。通过完整的代码示例和实战技巧,帮助读者掌握SAR成像处理算法,提升遥感图像处理能力。 阅读详情

相关推荐

Dify工作流教程|以抓取网页并更新知识库为例详细讲解工作流编排过程(附DSL文件)

{"name": "{新建的title变量}","text": "新建的content变量","indexing_technique": "high_quality","process_rule": {"mode": "automatic"}}有没有很痛苦,明明添加书签的网页,当你想阅读的时候,总是找不到或者好不容易找到了,发现网页404了。如果有个小工具,直接能把你输入的链接内容抓取下来,并且加入到你的知识库中,你说他香不香。无法获取授权的,也可以使用网页抓取工具,这个是免费的,抓取效果也可以。

同名公众号:dify实验室 1万+

Java集合篇:Hashtable原理详解(JDK1.8)

(本文使用的源码基于JDK1.8的)   一、Hashtable的基本方法: 这部分参考博客:https://blog.youkuaiyun.com/chenssy/article/details/22896871 1、定义: HashTable在Java中的定义如下: public class Hashtable&lt;K,V&gt; extends Dictionary&lt;K,V...

张维鹏的博客 3721

AI大模型与碳足迹评估结合模式及示范案例

AI大模型与碳足迹评估相结合,可以提供更精确、更快速的碳排放量计算,优化减排策略,并促进可持续发展目标的实现。

贾贾的博客 3943

【jdk8源码】HashTable集合

【jdk8源码】HashTable集合概述继承关系数据结构成员变量构造方法扩容和hash计算常用方法 概述 HashTable和HashMap类似,底层都是使用数组+单向链表实现,只是HashMap中多了一个转化红黑树的过程。HashTable不允许键值为空、遍历时无序、键不可重复、线程安全(在常用方法介绍里面可以看到,基本的操作方法例如put()、remove()等都使用了synchronized同步修饰)。 继承关系 public class Hashtable<K,V> exten

weixin_43988801的博客 280

VsCode+JLink+GCC替代Keil开发GD32程序-个人总结

对个人使用vscode+Jlink开发GD32程序做了总结,供需要者参考。

MyCollege1999的博客 2762

Dr_can Kalman Filter学习笔记(一)

本文是在b站Dr_can的卡尔曼滤波课程学习过程中的学习笔记

苏大侠的博客 1051

HashMap和HashTable的区别

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

sinat_26552841的博客 1万+

Ubuntu离线情况下安装gcc编译器

Ubuntu离线情况下安装gcc编译器1.系统版本2.安装说明3.异常处理 1.系统版本 (1)Ubuntu系统版本:20.04.1LTS; (2)gcc编译器版本:gcc-9.3.0(下载链接为https://download.youkuaiyun.com/download/qq_18350351/13762214); 当前可找到的gcc最新版本为gcc-10,但是笔者在安装gcc-10版本时发现一些依赖项无法安装,因此选取了gcc-9版本。如果是在联网情况下安装,直接使用apt相关的安装指令即可。 2.安装说明 安

GreenHand的博客 3932

HashMap和HashTable区别

Hashtable的查找、插入和删除操作平均时间复杂度为O(1),但是在极端情况下,因为哈希冲突的原因,可能会退化到O(n)。HashMap中可以存储null值和null键,但是要注意,当使用null作为键时,由于无法调用null的hashCode()方法,因此只能将其放在哈希表的第一个位置,它们是无序的。另外,由于HashMap采用链表和红黑树的数据结构,可以更好地处理哈希冲突,因此HashMap的查找、插入和删除操作都是常数时间O(1)。线程安全性指在多线程环境下,数据的并发访问是否会产生问题。

weixin_58724261的博客 1万+

执行HDevelop项目

这一节,我们讲述的是如何用HDevEngine加载和执行一个HDevelop项目。代码部分来源于示例程序exec_program(源文件exec_program.cpp),检测塑料零件边界上的毛刺。1.Step 1:初始化首先,我们包含HALCON/C++和HDevEngine头文件以及命名空间。注意到在这个示例程序中,HDevEngine头文件已经包含在my_hdevoperatorimpl中,所

Z's Palace 2994

锐明技术Crocus系统 DeviceState.do SQL注入漏洞复现

锐明技术Crocus系统 DeviceState.do 接口存在SQL注入漏洞,经过身份验证的远程攻击者除了可以利用SQL注入漏洞获取数据库中的信息(例如,管理员后台密码、站点的用户个人信息)之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限。

0xSec 453

HashTable和HashMap的区别详解

HashTable和HashMap的区别详解 一、HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。 HashMap是非线程...

weixin_30652491的博客 1708

OTA 升级失败/回滚策略设计:打造安全可靠的双分区/断点续传/签名校验方案

双分区机制(A/B Partitioning)是OTA升级的“保险箱”。简单来说,设备存储分为两个分区:A分区(当前运行)和B分区(备用)。升级时,新固件写入B分区,A分区保持不变。如果升级成功,系统切换到B分区运行;如果失败,设备直接回滚到A分区,完全不受影响。这就像玩游戏存档:你打Boss前存了个档,万一挂了还能读档重来。双分区就是设备的“读档”机制,避免了变砖的尴尬。以Android设备为例,Google从Android 7.0开始强制引入A/B分区机制(Seamless Updates)。

大模型大数据攻城狮的专栏 1235

HashMap和Hashtable的区别

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

xuhuaabc的博客 15万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

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

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ArrayList 和 Vector,HashMap 和 Hashtable的区别

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

chen2017sheng的博客 1104

HashMap 和 Hashtable 的区别

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

2301_80140022的博客 1514

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

HashMap和Hashtable区别?

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

exodus520的博客 1512

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万+
上一篇: CPU缓存与Java内存模型
下一篇: 从源码分析HashMap在JDK8与JDK7的变化
拾光机_Echo
博客等级 码龄14年 3粉丝 4原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值