HashSet如何保证元素唯一性?
来源:互联网 发布:android购物类app源码 编辑:程序博客网 时间:2024/04/27 12:33
Collection中的Set分为HashSet和TreeSet
Set中的元素是无序的,即存入和取出的顺序不一定一致,元素不可以重复。HashSet的底层数据结构是哈希表,元素存入的顺序是按照哈希值来排序的。
那么HashSet是如何保证元素唯一性的呢?
首先我们先直观地看看哈希值的样子
class Demo{}public class HashSetTest { public static void main(String[] args) { Demo d1=new Demo(); Demo d2=new Demo(); sop(d1); sop(d2); } public static void sop(Object obj){//定义此sop方法用来快捷输出,在输出较多的情况下尤为快捷。 System.out.println(obj); }}
HashCode就长这个样子
这些HashCode是如何产生的呢?
HashSet有一个方法叫做 int hashCode(),会在默认情况下产生无序的16进制hashcode值。
为了让其得到体现,我们可以直接将其重写:
在Demo类中重写hashCode()方法
class Demo{ public int hashCode() { return 60; }}public class HashSetTest { public static void main(String[] args) { Demo d1=new Demo(); Demo d2=new Demo(); sop(d1); sop(d2); } public static void sop(Object obj){ System.out.println(obj); }}
重写的效果就是,不管什么情况下,hashCode()方法都只返回一个hashCode值,60(16进制下为3c),所以其结果如下:
那么问题来了,由于HashSet是根据哈希值来排序的,那么如果有相同的哈希值的时候会发生什么情况?
再次举个例子,我们使用一个比较健全的自定义类,Person,此类有两个元素,String name和 int age,还有getName(),getAge()两个基础方法,再加上复写的hashCode()方法。定义HashSet对象hs。
class Person{ private String name; private int age; Person(String name,int age) { this.name=name; this.age=age; } public String getName() { return name; } public int getAge() { return age; } public int hashCode() { System.out.println(this.name+"......hashCode"); return 60; }}public class HashSetDemo { public static void sop(Object obj) { System.out.println(obj); } public static void main(String[] args) { HashSet hs=new HashSet<>(); hs.add(new Person("a1",11)); hs.add(new Person("a2",12)); hs.add(new Person("a2",12)); hs.add(new Person("a3",13)); Iterator it=hs.iterator(); while(it.hasNext()){ Person p=(Person)it.next(); sop(p.getName()+"::"+p.getAge()); } }}/*思路: * 1,对人描述,将数据封装进人对象 * 2,定义容器,将人存入 * 3,取出*/
运行结果前四句表示每一步都调用了复写完的hashCode()方法计算哈希值,后四句表示将a1,a2,a3都写入和新容器,且a2写了两次。
这个情况就是所有的a对象(转型到了hashSet),他们的hashcode都是一样的,依旧无法避免他们写入,没有保证元素的唯一性。
因为HashSet()保证元素唯一性是通过元素的两个方法,hashCode()和equals()来完成的。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,不会调用equals。
由于原始equals方法只适用于String的判断,不能识别name和age的组合,所以会出现重复的元素写入。
让我们重写一个适用于Person的equals方法
public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p=(Person)obj; System.out.println(this.name+"...."+p.name); return this.name.equals(p.name) && this.age == p.age; }
此方法实现了保证name和age都相同时视为重复元素。在hashCode()方法运行时会自动调用equals方法
第一句:计算a1哈希值,存入
第二句:计算a2哈希值,发现和a1一样为3c
第三句:a2和a1进行equals比较,不一样,存入
第四句:第二个a2来了,计算哈希值也是3c
第五句:第二个a2和第一个a2equals比较,一样,不存入
第六句:a3计算哈希值,为3c
七八句为a3和与其哈希值相同的a1,a2比较equals。
九,十,十一就是存入的结果,没有重复。
其实这是一种比较尴尬的状态,因为所有的元素哈希值都是一样的,这就意味着第2个元素要和第一个比较,第3个要和1,2比较,第4个要和1,2,3比较,第5个要和1,2,3,4比较,效率较低
所以做个优化,将hashCode()方法的return 60;换成return name.hashCode()+age*37;(37为随意取值)
完整代码
import java.util.*;class Person{ private String name; private int age; Person(String name,int age) { this.name=name; this.age=age; } public int hashCode() { System.out.println(this.name+"......hashCode"); return name.hashCode()+age*37; } public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p=(Person)obj; System.out.println(this.name+"....equals...."+p.name); return this.name.equals(p.name) && this.age == p.age; } public String getName() { return name; } public int getAge() { return age; }}public class HashSetDemo { public static void sop(Object obj) { System.out.println(obj); } public static void main(String[] args) { HashSet hs=new HashSet<>(); hs.add(new Person("a1",11)); hs.add(new Person("a2",12)); hs.add(new Person("a2",12)); hs.add(new Person("a3",13)); Iterator it=hs.iterator(); while(it.hasNext()){ Person p=(Person)it.next(); sop(p.getName()+"::"+p.getAge()); } }}
运行结果:
避免了重复比较。
总结:
Set:元素无序(存入和取出的顺序不一定一致),元素不可以重复。
HashSet:底层数据结构是哈希表。
HashSet如何保证 元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成的。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的HashCode和equals方法
先判断hashcode是否相同,如果相同再判断equals
!!(ArrayList判断和删除元素只依赖equals)
- HashSet如何保证元素唯一性?
- HashSet如何保证元素的唯一性
- HashSet保证元素唯一性
- 关于HashSet集合是如何保证元素唯一性的
- HashSet集合是如何保证元素的唯一性的?
- HashSet集合是如何保证元素的唯一性的?
- HashSet如何保证元素的唯一性-跟踪源码解析
- HashSet保证元素唯一性原理图解
- HashSet保证元素唯一性源码展示
- HashSet保证元素唯一性的原理
- 分析HashSet,HashMap源码,如何保证HashSet集合元素唯一性。
- java--基础----HashSet保证元素的唯一性
- 集合框架-HashSet存储元素保证唯一性的图解
- HashSet存储元素保证唯一性的代码及图解
- HashSet存储自定义对象如何保证唯一性
- HashSet存储自定义对象如何保证唯一性
- 黑马程序员——集合的特殊功能之HashSet集合如何保证元素的唯一性
- java学习笔记之 HashSet 保证元素唯一性的方法
- thinkphp5 数据库和模型详解 之3 模型和对象
- 正则表达式30分钟入门教程
- JAVA攻城狮学习路线
- Malaysia Mr.Cashback iBET SKY888 Slot Game
- 按位逻辑操作符那些事儿
- HashSet如何保证元素唯一性?
- [数据库]事务、并发、数据库锁
- RCU's CPU Stall Detector
- Apache Ambari 2.4.2 源码安全前的环境准备
- selenium中sendkeys()方法输入中文报错之解决方案
- 深入理解java虚拟机---类文件结构
- Git Cheat Sheet 中文版
- JS正则表达式大全(整理详细且实用)
- 欢迎使用CSDN-markdown编辑器