,,Java中的HashSet详解和使用示例_动力节点Java学院整理

,,Java中的HashSet详解和使用示例_动力节点Java学院整理

HashSet是一个没有重复元素的集合。接下来通过示例代码介绍java中hashset的知识。有兴趣的朋友来看看吧。

第1部分 HashSet介绍

HashSet 简介

HashSet是一个没有重复元素的集合。

它由HashMap实现,HashMap不保证元素的顺序,HashSet允许使用null元素。

HashSet是异步的。如果多个线程同时访问一个哈希集,并且其中至少有一个线程修改了该集,那么它必须保持外部同步。这通常是通过对自然封装集合的对象执行同步操作来完成的。如果不存在这样的对象,您应该使用Collections.synchronizedSet方法来“包装”该集合。最好在创建时这样做,以防止对该集合的意外异步访问:

set s=collections . synchronized set(new HashSet(.));

HashSet通过iterator()返回的迭代器是fail-fast。

HashSet的构造函数

//默认构造函数

公共哈希表()

//带有集合的构造函数

public HashSet(集合?扩展英中)

//指定HashSet的初始容量和加载因子的构造函数

公共哈希集(int initialCapacity,float loadFactor)

//指定哈希集初始容量的构造函数

公共哈希集(int initialCapacity)

//指定HashSet的初始容量和加载因子的构造函数。假人没有效果。

HashSet(int initialCapacity,float loadFactor,boolean dummy)

HashSet的主要API

布尔加法(E对象)

空清除()

对象克隆()

布尔包含(对象对象)

布尔型isEmpty()

迭代器迭代器()

布尔删除(对象对象)

int size()

第2部分 HashSet数据结构

HashSet的继承关系如下:

java.lang.Object

Java . util . abstract collection one

java.util.AbstractSetE

Java . util . hash set

公共类哈希特

扩展抽象集

实现SetE,Cloneable,java.io.Serializable { }

HashSet和Map之间的关系如下:

从图中可以看出:

(01) HashSet从AbstractSet继承,实现Set接口。

(02)hashset的本质是一个“没有重复元素”的集合,通过HashMap实现。HashSet包含一个HashMap类型的成员变量‘map’,HashSet的操作函数实际上是由map实现的。

第3部分 HashSet源码解析(基于JDK1.6.0_45)

为了更好的理解HashSet的原理,下面对HashSet的源代码进行分析。

包java.util

公共类哈希特

扩展抽象集

实现SetE、Cloneable、java.io.Serializable

{

static final long serial version uid=-5024744406713321676 l;

//HashSet通过map(HashMap对象)保存内容

私有瞬态HashMapE,对象映射;

//PRESENT是将key-value对应的值插入到映射中。

//因为HashSet中只需要key,而HashMap是键值键值对;

//所以,在添加键值对进行映射时,键值对的值固定为PRESENT。

私有静态最终对象PRESENT=new Object();

//默认构造函数

public HashSet() {

//调用HashMap的默认构造函数创建映射

map=new HashMapE,Object();

}

//带有集合的构造函数

public HashSet(集合?扩展E c) {

//创建地图。

//为什么要调用math.max ((int) (c.size()/.75f) 1,16)并从(c.size()/.75f) 1和16中选择更大的树?

//首先解释一下(c.size()/.75f) 1

//因为考虑到HashMap的效率(时间成本和空间成本),HashMap的加载因子是0.75。

//当HashMap的“threshold”(threshold=HashMap的总大小*加载因子)“HashMap的实际大小”时,

//你需要把HashMap的容量增加一倍。

//所以,用(c.size()/.75f) 1计算出来的正好是总的空间大小。

//接下来解释一下为什么是16。

hashmap的总大小必须是2的指数倍。如果创建HashMap时指定的大小不是2的指数倍数;

//也会在HashMap的构造函数中重新计算,找出大于“指定大小”的2的最小指数倍的个数。

//所以,这里指定16是出于性能考虑。避免重复计算。

map=new HashMapE,Object(math . max((int)(c . size()/. 75f)1,16));

//将集合(三)中的全部元素添加到哈希特中

addAll(c);

}

//指定哈希特初始容量和加载因子的构造函数

公共哈希集(int initialCapacity,float loadFactor) {

map=new HashMapE,Object(initialCapacity,load factor);

}

//指定哈希特初始容量的构造函数

公共哈希集(int initialCapacity) {

map=new HashMapE,Object(初始容量);

}

HashSet(int initialCapacity,float loadFactor,boolean dummy) {

map=new LinkedHashMapE,Object(initialCapacity,load factor);

}

//返回哈希特的迭代器

公共迭代器迭代器(){

//实际上返回的是散列表的"钥匙集合的迭代器"

返回map.keySet().迭代器();

}

public int size() {

返回地图。size();

}

public boolean isEmpty() {

返回地图。isempty();

}

公共布尔包含(对象o) {

返回地图。包含键(o);

}

//将元素(五)添加到哈希特中

公共布尔加法(E e) {

return map.put(e,PRESENT)==null;

}

//删除哈希特中的元素(o)

公共布尔移除(对象o) {

返回地图。remove(o)==PRESENT;

}

公共void clear() {

地图。clear();

}

//克隆一个哈希集,并返回目标对象

公共对象克隆(){

尝试{

哈希集合newSet=(哈希集合)super。clone();

newSet.map=(HashMapE,Object)map。clone();

返回新闻集

} catch(CloneNotSupportedException e){

抛出新的内部错误();

}

}

//java.io.Serializable的写入函数

//将哈希特的"总的容量,加载因子,实际容量,所有的元素"都写入到输出流中

私有void writeObject(Java。io。对象输出流

抛出java.io.IOException {

//写出任何隐藏的序列化魔术

s。defaultwriteobject();

//写出散列表容量和加载因子

s。写int(map。容量());

s。写浮点(映射。负载系数());

//写出大小

s。写int(map。size());

//按照正确的顺序写出所有元素。

对于(迭代器i=map.keySet().迭代器();I .有next();)

s。writeobject(I . next());

}

//java.io.Serializable的读取函数

//将哈希特的"总的容量,加载因子,实际容量,所有的元素"依次读出

私有void读取对象(Java。io。对象输入流

抛出java.io.IOException,ClassNotFoundException {

//读入任何隐藏的序列化魔术

s。默认读取对象();

//读入哈希表容量和加载因子,并创建后备哈希表

int capacity=s . readint();

浮点加载因子=s . read float();

map=(((HashSet)this)链接HashSet的instanceof?

新的LinkedHashMapE,Object(capacity,loadFactor):

new HashMapE,Object(capacity,load factor));

//读入大小

int size=s . readint();

//以正确的顺序读入所有元素。

for(int I=;isizei ) {

E E=(E)s . read object();

map.put(e,PRESENT);

}

}

}

说明:哈希集的代码实际上非常简单,通过上面的注释应该很能够看懂。它是通过散列表实现的,若对哈希特的理解有困难,建议先学习以下散列表学完散列表之后,在学习哈希特就非常容易了。

第4部分 HashSet遍历方式

4.1 通过Iterator遍历HashSet

第一步:根据迭代器()获取哈希特的迭代器。

第二步:遍历迭代器获取各个元素。

//假设设置是哈希特对象

for(Iterator迭代器=集合。迭代器();

迭代器。有next();) {

迭代器。next();

}

4.2 通过for-each遍历HashSet

第一步:根据托阵列()获取哈希特的元素集合对应的数组。

第二步:遍历数组,获取各个元素。

//假设设置是哈希特对象,并且设置中元素是线类型

String[]arr=(String[])集。to数组(新字符串[0]);

对于(字符串字符串:arr)

系统。出去。printf(' for each:% s \ n ',str);

哈希特的遍历测试程序如下:

导入Java。util。随机;

导入Java。util。迭代器;

导入Java。util。hashset

/*

* @desc介绍哈希特遍历方法

*

*

*/

公共类HashSetIteratorTest {

公共静态void main(String[] args) {

//新建哈希特

HashSet set=new HashSet();

//添加元素到哈希特中

for(int I=;我;我)

设置。add(“I”);

//通过迭代程序遍历哈希特

iteratorHashSet(集合);

//通过对于每个人遍历哈希特

foreachHashSet(集合);

}

/*

* 通过迭代程序遍历哈希集。推荐方式

*/

私有静态空的迭代器哈希集(哈希集){

for(Iterator迭代器=集合。迭代器();

迭代器。有next();) {

系统。出去。printf('迭代器:% s \ n ',迭代器。next());

}

}

/*

* 通过对于每个人遍历哈希集。不推荐!此方法需要先将一组转换为数组

*/

私有静态void foreachHashSet(HashSet集){

String[]arr=(String[])集。to数组(新字符串[]);

对于(字符串字符串:arr)

系统。出去。printf(' for each:% s \ n ',str);

}

}

运行结果:

迭代器:3

迭代器:2

迭代器:1

迭代器:0

迭代器:4

每个:3

每个:2

每个:1

对于每个:0

每个:4

第5部分 HashSet示例

下面我们通过实例学习如何使用哈希特

导入Java。util。迭代器;

导入Java。util。hashset

/*

* @ desc哈希特常用应用程序接口的使用。

*

* @作者天行

*/

公共类HashSetTest {

公共静态void main(String[] args) {

//哈希集常用应用程序接口

testHashSetAPIs();

}

/*

*哈希集除了迭代器()和添加()之外的其它常用应用程序接口

*/

私有静态void testHashSetAPIs() {

//新建哈希特

HashSet set=new HashSet();

//将元素添加到一组中

设置。添加(' a ');

设置。添加(' b ');

设置。add(' c ');

设置。add(' d ');

设置。添加(' e ');

//打印哈希特的实际大小

System.out.printf('size : %d\n ',set。size());

//判断哈希特是否包含某个值

系统。出去。printf(' HashSet包含一个:% s \ n ',Set。包含(' a ');

系统。出去。printf(' HashSet包含g:% s \ n ',Set。包含(' g ');

//删除哈希特中的" e "

设置。删除(' e ');

//将一组转换为数组

String[]arr=(String[])集。to数组(新字符串[]);

对于(字符串字符串:arr)

系统。出去。printf(' for each:% s \ n ',str);

//新建一个包含b、c、f的哈希特

HashSet other set=new HashSet();

另一套。添加(' b ');

另一套。add(' c ');

另一套。添加(' f ');

//克隆一个removeset,内容和设置一模一样

HashSet remove set=(HashSet)set。clone();

//删除"删除集中,属于其他集合的元素"

移除套件。全部删除(其他设置);

//打印移除集

系统。出去。printf('移除集合:% s \ n ',移除集合);

//克隆一个保留集,内容和设置一模一样

HashSet retain set=(HashSet)set。clone();

//保留"保留集中,属于其他集合的元素"

保留设置。保留全部(其他集);

//打印保留集

系统。出去。printf(' retainset:% s \ n ',retainset);

//遍历哈希特

for(Iterator迭代器=集合。迭代器();

迭代器。有next();)

系统。出去。printf('迭代器:% s \ n ',迭代器。next());

//清空哈希特

设置。clear();

//输出哈希特是否为空

System.out.printf('%s\n ',set.isEmpty()?“集为空”:“集不为空”);

}

}

运行结果:

尺寸:5

哈希特包含一个:正确

哈希特包含高:错

每个:d

每个:b

每个:c

每个:一个

移除集:[d,a]

保留集:[乙,丙]

迭代器:d

迭代器:b

迭代器:c

迭代器:a

集合为空

以上所述是小编给大家介绍的Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)中的哈希特详解和使用示例_动力节点Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)学院整理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: