Java系列文章目录
补充内容 Windows通过SSH连接Linux
第一章 Linux基本命令的学习与Linux历史
一、前言
- 使用HashSet对类对象去重失败
二、学习内容:
- HashSet去重的原理
三、问题描述
- 当参数是一个类的时候
- HashSet无法去重
输出还是两条一样的
四、解决方案:
4.1 部分功能概况
- HashSet部分功能
4.2 问题原因与解决
Object里面的equals方法默认比较的就是地址值,t1和t2的地址值不一致,所以HashSet认为这是两个不同的对象,所以我们需要重写方法。
重写 hashCode() 和 equals() 方法与 HashSet 的去重机制密切相关。
- 在 Java 中,HashSet 是基于 HashMap 实现的一个不包含重复元素的集合。当向 HashSet添加一个对象时,它首先计算该对象的哈希码 (hashCode()),然后使用该哈希码来确定对象在哈希表中的位置。如果两个对象的哈希码相同,那么它们可能会映射到同一个桶(bucket)中。
重写方法:
解决方法
hashCode() 方法:
- 应该返回一个整数值,这个值是对象的一个哈希码。
- 如果两个对象相等(即 equals() 返回 true),那么它们的 hashCode() 必须返回相同的值。
- 如果两个对象不相等,它们的 hashCode() 方法返回的值不一定不同,但是不同的哈希码有助于提高哈希表的性能。
equals() 方法:
- 用来判断两个对象是否相等。
- 如果 equals() 方法返回 true,那么两个对象的 hashCode() 方法应该返回相同的值。
- 如果 equals() 方法返回 false,那么 hashCode() 方法的返回值可以相同或不同。
源码具体实现:
- 其中 hash(key) 方法会调用 key.hashCode() 来获取哈希码。putVal方法则负责实际的插入操作,它会检查是否有哈希码相同的键存在,如果有,则会调用 equals 方法进一步确认键是否相等。
五、总结:
5.1 学习总结:
- Object中是比较值所以可以去重但是对象要重写方法
- 注意需要重写两个方法才能去重
在 HashSet 中,当添加一个新对象时,如果发现有哈希码相同的对象,就会进一步调用 equals() 方法来进行比较。这个过程发生在 HashMap 的 put 方法中,因为 HashSet 实际上是基于 HashMap 实现的。
HashSet 的 add 方法:
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
- 这里 map 是 HashSet 内部的 HashMap,PRESENT 是一个静态对象,用于标记 HashSet 中的元素。
HashMap 的 put 方法:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
- 这里的 hash(key) 方法会调用 key.hashCode() 来获取哈希码。
HashMap 的 putVal 方法:
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
break;
}
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
- 在这里,可以看到当 HashMap 的 put方法被调用时,它会首先计算哈希码,然后定位到相应的桶(bucket)。如果桶中已经有哈希码相同的对HashMap会遍历桶中的链表,并对每个对象调用 key.equals(k) 方法来进行比较。
equals 方法的调用:
- 如果桶中的某个对象的哈希码与新对象的哈希码相同,HashMap 会调用 key.equals(k)方法来进一步确认这两个对象是否相等。如果 equals 方法返回 true,那么 HashMap认为这两个对象是相等的,因此不会添加新对象。如果 equals 方法返回 false,则认为这两个对象是不相等的,新对象会被添加到桶中。
(后续有遇到问题再添加)
声明:如本内容中存在错误或不准确之处,欢迎指正。转载时请注明原作者信息(麻辣香蝈蝈)。