HashSet如何保证元素的唯一性-跟踪源码解析

自己的理解:HashSet的底层数据结构用的是哈希表(HashMap),当往HashSet上添加一条元素时。

public boolean add(E e) {

return map.put(e, PRESENT)==null;//PRESENT是一个一样的Object对象,调用HashMap的put方法

}

点进put方法如下:

public V put(K key, V value) {

if (table == EMPTY_TABLE) {

inflateTable(threshold);

}

if (key == null)

return putForNullKey(value);

int hash = hash(key);

int i = indexFor(hash, table.length);

for (Entry<K,V> e = table[i]; e != null; e = e.next) {

Object k;

if (e.hash == hash && ((k = e.key) == key ||key.equals(k))) {

V oldValue = e.value;

e.value = value;

e.recordAccess(this);

return oldValue;

}

}

modCount++;

addEntry(hash, key, value, i);

return null;

}

进入hash(key)方法:

//利用hashCode()方法返回一个hash值

final int hash(Object k) {

int h = hashSeed;

if (0 != h && k instanceof String) {

return sun.misc.Hashing.stringHash32((String) k);

}

h ^= k.hashCode();

h ^= (h >>> 20) ^ (h >>> 12);

return h ^ (h >>> 7) ^ (h >>> 4);

}

答案明显易见:当HashSet添加一条元素时,调用HashMap的put方法先调用hashCode()方法判断key的hash值是否一样,再调用对象的equals方法。

总结:

当HashSet中放入了两个对象后,默认他们的hashCode都是不一样的,因此不需要调用equals方法就能确定这两个对象不是同一个,但是如果这两个对象的值是一样的,这种判断结果就不符合要求了,因此需要重写hashcode方法,将两个对象的hashcode值设为相同,这样就可以进入equals判断阶段,equals方法是继承自object类的,比较的是对象的地址值,所以判断的结果也必定不同,这又不符合要求了,因此也需要重写equals方法。经过改写以上两个方法,可以完成两个对象的比较,只要两个对象的内容(值)相同,就判断为同一个对象,不得重复存储。哈希表就像一个个桶,每个桶都有一个hashcode,只要元素的hashcode相同,equals如果为false,那么这些元素都挂在这个桶里。

另外,判断是否包含某元素(contains),list和set也是不同的:

ArrayList:判断包含,以及删除,都是依据元素的equals方法。

HashSet:判断包含,以及删除,都是依据元素的hashCode方法。当hashCode值相同时,在判断一次equals方法。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 16:03:45

HashSet如何保证元素的唯一性-跟踪源码解析的相关文章

解说HashSet如何保证元素的唯一性

HashSet底层数据结构是哈希表,哈希表按哈希值来存储,HashSet集合中有若干个存储区域,而每个对象可以计算出一个hash值,系统会自动将这个值分组,对应若干个存储区域.当添加新元素时,系统会计算出这个元素的hash值,然后跟存储区域的每一个元素进行比较,如果不相同则添加该新元素.如果相同再equals比较,若为false,则添加该元素. 简单说就是同过元素的两个方法,hashcode()和equals()来完成,如果元素的hashCode值相同,再判断equals是否为true,若为tr

第六章 HashSet源码解析

6.1.对于HashSet需要掌握以下几点 HashSet的创建:HashSet() 往HashSet中添加单个对象:即add(E)方法 删除HashSet中的对象:即remove(Object key)方法 判断对象是否存在于HashSet中:containsKey(Object key)  注:HashSet没有获取单个对象的方法,需要使用iterator 6.2.构建HashSet 源代码: //HashSet底层数据结构:通过hashmap的key不可重复的原则,使得存放入HashSet

HashSet源码解析

今天来介绍下HashSet.前面,我们已经系统的对List和Map进行了学习.接下来,我们开始可以学习Set.相信经过Map的了解之后,学习Set会容易很多.毕竟,Set的实现类都是基于Map来实现的(HashSet是通过HashMap实现的). 构造图如下: 蓝色线条:继承 绿色线条:接口实现 正文 对于HashSet而言,它是基于HashMap来实现的,底层采用HashMap来保存元素.所以如果对HashMap比较熟悉,那么HashSet是so easy!! HashSet简介 HashSe

JDK 源码解析 —— HashSet

零. 简介 这个类实现了 Set 接口,内部是由 HashMap 实例辅助实现的.它不保证元素的顺序,数据允许为 null. 假如 hash 方法将数据分散地比较合理,比如一个 bucket 一个数据,那么 add.remove.contains.size 性能开销是常数时间. 这个类非线程安全的,如果多线程并发访问,并且至少一个线程在做修改操作,那么必须在外部做好同步处理.例如使用:Set s = Collections.synchronizedSet(new HashSet(...)); 一

【转】Java 集合系列16之 HashSet详细介绍(源码解析)和使用示例--不错

原文网址:http://www.cnblogs.com/skywang12345/p/3311252.html 概要 这一章,我们对HashSet进行学习.我们先对HashSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashSet.内容包括:第1部分 HashSet介绍第2部分 HashSet数据结构第3部分 HashSet源码解析(基于JDK1.6.0_45)第4部分 HashSet遍历方式第5部分 HashSet示例 转载请注明出处:http://www.cnblogs.

Java HashSet源码解析

本解析源码来自JDK1.7,HashSet是基于HashMap实现的,方法实现大都直接调用HashMap的方法 另一篇HashMap的源码解析文章 概要 实现了Set接口,实际是靠HashMap实现的 不保证遍历时的顺序,不保证集合顺序的不变性 HashSet允许出现null值 假定Hash算法能很好的分散元素,查询的时间复杂度为O(1) 遍历的时间复杂度由set的size和其依靠的HashMap的capacity来决定 HashSet是非同步的可以通过Set s = Collections.s

Java 集合系列16之 HashSet详细介绍(源码解析)和使用示例

概要 这一章,我们对HashSet进行学习.我们先对HashSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashSet.内容包括:第1部分 HashSet介绍第2部分 HashSet数据结构第3部分 HashSet源码解析(基于JDK1.6.0_45)第4部分 HashSet遍历方式第5部分 HashSet示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3311252.html 第1部分 HashSet介绍 HashSet 简

给jdk写注释系列之jdk1.6容器(6)-HashSet源码解析&amp;Map迭代器

今天的主角是HashSet,Set是什么东东,当然也是一种java容器了. 现在再看到Hash心底里有没有会心一笑呢,这里不再赘述hash的概念原理等一大堆东西了(不懂得需要先回去看下HashMap了),需要在啰嗦一句的是hash表是基于快速存取的角度设计的,也是一种典型的空间换时间的做法(这个在分析HashMap中都有讲过).那么今天的HashSet它又是怎么一回事的,他的存在又是为了解决什么问题呢? 先来看下Set的特点:Set元素无顺序,且元素不可以重复. .想到了什么?无顺序,由于散列的

jquery源码解析:jQuery对元素属性的操作2

这一课,我们将继续讲解jQuery对元素属性操作的方法. 首先,我们先看一下这几个方法是如何使用的: $("#div1").addClass("box1 box2");     //给元素div的class属性添加box1和box2 $("#div1").removeClass("box1");     //删除元素div的class属性值box1 $("#div1").toggleClass("