HashMap、Hashtable、HashSet

一、HashMap(API文档

//所在包
package java.util;

//继承关系
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {}

HashMap是基于哈希表的Map接口的实现,当假设散列函数在桶之间正确地分散元素(均匀散列)时,基本读写操作( get和put )提供了常数(O(1))时间性能。HashMap有两个影响其性能的参数: 初始容量和负载因子 。 容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。 负载因子是在自动增加容量之前允许哈希表存储的Key-Value的数量与桶的数量的最大比例。 当哈希表中键值对的数量超过加载因子和当前容量的乘积时,哈希表将被重新构建(即重新分配容量),一遍是使哈希表增加一倍。一般默认加载因子(.75)在时间和空间成本之间提供了良好的折衷。在设置其初始容量时,必须要考虑映射中预期Key-Value的目数及其负载因子,以便最小化重新散列。 如果初始容量大于最大条目数除以加载因子,则不会发生增加容量。

HashMap的冲突解决方法是散列链表(其他冲突解决方法包括 开发地址等),使用较多具有相同hashCode()的Key键会产生冲突,且冲突必然降低哈希表性能,若Key是一组可比较大小的数据时,可以有效避免冲突。

  1. HashMap提供了所有可选的映射操作,并允许null值和null键(HashMap类大致相当于Hashtable ,除了它是不同步的并且允许空值)
  2. HashMap不保证Key-Value的顺序; 特别是容量增加后,HashMap不保证Key-Value的顺序会随着时间的推移保持不变。
  3. HashMap不是线程同步的(Hashtable支持同步),如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步(结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改)。可使用Collections.synchronizedMap方法修饰HashMap的实例Map m = Collections.synchronizedMap(new HashMap(...));

在这里插入图片描述
在这里插入图片描述
二、Hashtable(API文档

//所在包
package java.util;

//继承关系
public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {}

Hashtable类实现了一个哈希表,它将键映射到值。 要成功存储和检索哈希表中的对象,用作键的对象必须实现hashCode方法和equals方法。Hashtable的实例有两个影响其性能的参数: 初始容量和负载因子 。 容量是哈希表中的桶数, 初始容量只是创建哈希表时的容量。 请注意,哈希表是打开的 :在“哈希冲突”的情况下,单个存储桶存储多个条目,必须按顺序搜索。 负载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。 初始容量和负载系数参数仅仅是实现的提示。 关于何时以及是否调用rehash方法的确切细节是依赖于实现的。通常,默认负载系数(.75)在时间和空间成本之间提供了良好的折衷。 较高的值会减少空间开销,但会增加查找条目的时间成本(这反映在大多数Hashtable操作中,包括get和put )。初始容量控制了浪费空间与rehash操作需求之间的权衡,这是非常耗时的。 如果初始容量大于Hashtable将包含的最大条目数除以其加载因子,则将不会发生rehash操作。 但是,将初始容量设置得太高会浪费空间。如果要在Hashtable中创建许多条目,则使用足够大的容量创建条目可能允许更高效地插入条目,而不是根据需要执行自动重新分组来扩展表。

  1. 任何非null对象都可以用作键或值
  2. HashMap是线程同步的(如果不需要线程安全实现,建议使用HashMap代替Hashtable),如果需要线程安全的高度并发实现,则建议使用ConcurrentHashMap代替Hashtable
  3. 如果在创建迭代器之后的任何时候对Hashtable进行结构修改,除非通过迭代器自己的remove方法,迭代器将抛出ConcurrentModificationException 。
Hashtable<String, Integer> numbers = new Hashtable<String, Integer>(); 
numbers.put("one", 1); 
numbers.put("two", 2); 
numbers.put("three", 3);

 Integer n = numbers.get("two"); 
 if (n != null) 
 	{ 
 		System.out.println("two = " + n); 
 	} 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三、HashSet(API文档

package java.util;

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable{}

HashSet实现Set接口,由哈希表(实际上是HashMap实例)支持。 它不保证集合的迭代顺序; 特别是,它不保证订单会随着时间的推移保持不变。提供了基本的操作(固定时间性能add , remove , contains和size ),假定哈希函数将分散的桶中正确的元素。 迭代此集合需要的时间与HashSet实例的大小(元素数量)加上后备HashMap实例的“容量”(桶数)之和成比例。 因此,如果迭代性能很重要,则不要将初始容量设置得太高(或负载因子太低)非常重要。如果在创建迭代器之后的任何时间修改该集,除了通过迭代器自己的remove方法之外,迭代器抛出ConcurrentModificationException 。

  1. HashSet允许null元素
  2. HashSet实现不同步。 如果多个线程同时访问哈希集,并且至少有一个线程修改了该集,则必须在外部进行同步。 这通常通过在自然封装集合的某个对象上进行同步来实现。 如果不存在此类对象,则应使用Collections.synchronizedSet方法“包装”该集合 。 这最好在创建时完成,以防止对集合的意外不同步访问:Set s = Collections.synchronizedSet(new HashSet(...));

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值