1 java类中HashSet添加对象时,为什么一定要重写equals方法和HasCode方法?
a Set集合没有顺序,也不允许重复,为什么会这样?
答:是为了模拟现实的集合。
b 重复这里在现实中和内存中有什么区别?
答:现实中的重复指的是对象的重复,而内存中的重复指的hashCode的重复。
c 由于现实中和内存中的重复不同,存在一种情况,在内存中重复(hashCode)相同,现实中不是同一个对象,这种例子呢?
答:代码如下,debug可以看到两个person对象的hash码相同,其属性相同:
package com.array.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class TestHashSet2 { public static void main(String[] args) { Person p1 = new Person("a", 1); Person p2 = new Person("b", 0); Set<Person> set = new HashSet<Person>(); set.add(p1); set.add(p2); Iterator<Person> it = set.iterator(); while (it.hasNext()) { System.out.println(it.next().getName()); } } }
package com.array.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; class Person { private String name; private int id; Person(String name, int id) { this.name = name; this.id = id; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setId(int id) { this.id = id; } public int getId() { return id; } public int hashCode() { return name.hashCode() + id; // 使用字符串哈希值与Integer的哈希值的组合 // 这样会产生重码,实际上重码率很高 } public boolean equals(Object obj) { if (obj instanceof Person) { // Person p = (Person) obj; return (name.equals(p.name) && id == p.id); } return super.equals(obj); } }
d 为了解决c这种情况(现实中的重复与内存的重复不一致),我们应该怎么做呢?
答:c代码已经给了明显的答案。
HashSet添加对象的时候,先用hashCode方法计算出该对象的哈希码。
比较:
(1),如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中!
(2),如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象(判断的标准是:属性是否相同)
1>,相同对象,不添加。
2>,不同对象,添加!
至此,1问题得到了解答。
-
总思路:hashCode不同时,则必为不同对象。hashCode相同时,根据equlas()方法判断是否为同一对象。
-
在HashSet,HashMap,HashTable中都存在该问题。
2 为什么重写Equals方法必须重写HashCode方法?
答:1、将要传入的数据根据系统的hash算法得到一个hash值;
2、根据hash值可以得出该数据在hash表中的位置;
3、判断该位置上是否有值,没有值则把数据插入进来;如果有值则再次判断传入的值与原值是否地址或equals相同,如果相同则不存,否则通过链表的方式 存储到该位置。
如果两个对象equals,但是没有重写hashcode,就会导致集合中可能存储多个相等的对象!所以必须重写!
引自:
https://jingyan.baidu.com/article/d5a880eb8fb61d13f147cc99.html
https://www.cnblogs.com/shew/p/11370804.html