Java中HashSet集合如何控制 元素唯一性 总结

近期在学习HashSet集合,HashSet集合的特点就是:该集合中的元素唯一,无序。而第一个特点 “唯一” 就是学习HashSet集合的重点!

例子:no.1新建一个HashSet集合对象 hs;

    no.2新建四个Student对象 st1(“张三”,18), st2(“李四”,19), st3(“王五”,20), st4(“张三”,18);

    no.3把四个学生对象放到集合中   hs.add(st1);   hs.add(st2);   hs.add(st3);   hs.add(st4);

    no.4用增强for来遍历输出集合中的元素 for(Student s:hs){
System.out.println(s.getAge()+"    "+s.getName());
}

结果: 张三  18

李四  19

王五  20

张三  18

为什么集合中存在相同元素呢??

/*注意:1.HashSet里面的add方法实际是调用的hashCode()方法和equals()方法来保证元素的唯一性;底层的逻辑是这样的:

先判断两个对象的hashCode是否相同:

如果不相同认为俩对象不相同,就往集合里面添加元素

如果相同,再用equals方法判断俩对象的所有的成员变量是否相同:

俩对象的所有的成员变量都相同,则认为俩对象相同,不往集合里面添加元素

俩对象的至少有一个成员变量相同,则认为俩对象相同,往集合里面添加元素

HashSet——>Set——>collection——>object   集合之间的继承关系是这样的,自然,HashSet调用的就是object类的hashCode()方法;而,object类的hashCode方法比较的是俩对象的地址值(默认情况下,Object中的hashCode() 返回对象的32位jvm内存地址。也就是说如果对象不重写该方法,则返回相应对象的32为JVM内存地址。),用new来新建对象根本不可能存在地址值相同的对象,也就是说任何俩对象的hashCode值都不相同;那么就立即往集合里面添加元素,所以就会有相同的元素出现


在上面的例子中
 *       由于Student类没有重写hashCode()方法和equals()方法,
 *    所以实际上调用的是object的hashCode()方法和equals()方法
 *    这个时候,每个对象的哈希值不一样的,在底层就根本不用equals()比较
 *    而是直接添加元素

但我们要注意,我们自己定义的类没有重写hashCode()和equals()方法;而当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()hashCode()方法时,已经覆盖了object类的hashCode()和equals()方法

1.     hashcode() 方法,在object类中定义如下:

  public native int hashCode(); 说明是一个本地方法,它的实现是根据本地机器相关的。

当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double。。。。等等这些类都是覆盖了 hashcode()方法的。

例如在String类中定义的hashcode()方法如下: 

public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; } 解释一下这个程序(String的API中写 到): s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度, ^ 表示求幂。(空字符串的哈希码为 0。) 

2.     equals()方法在object类中定义如下: public boolean equals(Object obj) { return (this == obj); } 很明显是对两个对象的地 址值进行的比较(即比较引用是否相同)。

比如在String类中如下: 

public boolean equals(Object anObject) 

if (this == anObject) {

  return true; 

if (anObject instanceof String) {

 String anotherString = (String)anObject; 

int n = count; 

if (n == anotherString.count) {

 char v1[] = value; 

char v2[] = anotherString.value; 

int i = offset; 

int j = anotherString.offset; 

while (n-- != 0) { 

if (v1[i++] != v2[j++])

  return false; 

return true; } 

return false;

很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。

另外:

这里我们首先要明白一个问题:  equals()相等的两个对象,hashcode()一定相等;

 equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。

换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码 在生成的时候产生冲突造成的)。

 反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等, 也可能不等。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java集合HashSet是一种基于哈希表实现的集合,它继承自AbstractSet并实现了Set接口。HashSet提供了高效的查找、插入和删除操作,可以存储不重复的元素HashSet的构造方法有四种形式:HashSet()、HashSet(int initialCapacity)、HashSet(int initialCapacity, float loadFactor)和HashSet(Collection<? extends E> c)。 你可以使用以下代码来创建一个HashSet集合: 1. 使用无参构造方法: HashSet<Integer> set = new HashSet<>(); 2. 使用指定初始容量的构造方法: HashSet<Integer> set1 = new HashSet<>(20); 3. 使用指定初始容量和负载因子的构造方法: HashSet<Integer> set2 = new HashSet<Integer>(20, 0.8f); 4. 使用指定集合的构造方法: HashSet<Integer> set3 = new HashSet<>(new ArrayList<Integer>()); 使用HashSet集合时,需要注意元素唯一性和哈希值的计算,HashSet内部使用哈希函数来计算元素的哈希值,并根据哈希值来存储和查找元素。当两个元素的哈希值相同时,HashSet会通过equals()方法来判断它们是否相等。在使用HashSet时,建议重写equals()和hashCode()方法,以确保元素唯一性和正确的哈希值计算。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java集合HashSet](https://blog.csdn.net/friend_X/article/details/113755564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值