我们都知道,HashSet和HashMap的存储形式都是: 哈希表+链表/红黑树
以HashMap为例,相同哈希值的数据产生哈希冲突,以链表或红黑树的形式存储。为确保Map中不含有重复元素,需要重写数据类的equals()方法以及HashCode()方法。
当重写HashCode方法时,向Objects.hash()中传入的参数就是生成HashCode的依据。
public class Person {
private String name;
private int age;
private int height;
public Person() {
}
public Person(String name, int age, int height) {
this.name = name;
this.age = age;
this.height = height;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
这里的参数只有name和age,那么在创建Person对象时,只要name值和age值相等,那么两者的HashCode值就相等。
public class HashCodeTest {
public static void main(String[] args) {
Person p1 = new Person("cky",21,174);
Person p2 = new Person("cky",21,175);
int i1 = p1.hashCode();
int i2 = p2.hashCode();
System.out.println(i1 == i2); //true
}
}
因为HashCode值相等,所以在两个Person对象在向HashMap中存储时就会产生哈希冲突,这时会判断equals方法,如下代码所示。
public class HashCodeTest {
public static void main(String[] args) {
Person p1 = new Person("cky",21,174);
Person p2 = new Person("cky",21,175);
HashMap<Person,String> map = new HashMap<>();
map.put(p1,"666");
map.put(p2,"999");
Set<Map.Entry<Person, String>> set = map.entrySet();
for (Map.Entry<Person, String> entry : set) {
Person key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "-->" + value);
}
}
}
因为equals方法的比较标准同样为name和age,所以p1和p2被认定为同一元素,即key值相等,那么在添加<p2, “999”>键值对时,就会对<p1, “666”>键值对中的values值进行覆盖,而key值却不发生改变,仍为p1,这时键值对为<p1, “999”>,遍历结果为:
那么如何“骗过”equals方法,从而使得p1和p2都能成功得添加成功而不被认定为重复元素呢?这里我们重写Person类中的equals方法。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
height == person.height;
}
以上将判断是否相同的标准改为age和height(HashCode的生成标准仍为name和age),再次运行测试类,此时的遍历结果就发生了改变。
通过本次测试,我们可以得出答案,不同对象的HashCode值可以相等。通过本测试还理清了HashMap的判别机制,以上。