Object中的equals( )方法是去比较两个对象是不是同一个对象,即比较两个对象的地址是不是相等。是的话返回true。hashCode( )方法则是返回对象的内部地址表示。
当我们自己实现一个类,但是没有实现这两个方法的话,会出现什么情况?
一、首先明确这两个方法在HashMap中的意义:
1、hashCode( ):
当我们执行put( )操作时,主要用来确定key需要被存放到哪个slot(即hash桶)
当我们执行get( )操作时,主要用来确定key被存放的slot(即hash桶)
2、equals( ):
- 当我们执行put( )操作时且已经确定了key的slot,如果slot中已经存了一些keys,则需要去遍历这些keys,如果有一个key和要put的key相等(equals返回true),则会替换旧值。
- 当我们执行get( )操作时且已经确定了key的slot,对于该slot中已经存的keys进行遍历,如果hash值相等且equals返回true,则该key就是我们要找的。
二、如果class没实现hashCode( )方法,会怎样?
每次存放对象时,用该对象的地址作为hashCode去定位slot,貌似不会产生问题,但是有可能会因为hash值的分散性不够好,导致一个slot中插入过多的keys。
而且对于原本相等的两个对象,有可能因为hash值不等,放在了两个不同的slot中。
三、如果class没实现equals( )方法,会怎样?
当我们连续put两个看上去相等的对象时(但是equals返回false),第二次put原本是打算修改第一个put时的value值,但是两次put插入了两个key,也就是说并没有覆盖第一个key的value。
当我们用一个对象去get( )时,所使用的对象看似和想要获取的对象相等,实际上equals返回false。会返回null,或者得到的根本不是自己想要的。
四、只实现hashCode,没实现equals
static class People {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
/*@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age &&
Objects.equals(name, [people.name](http://people.name));
}*/
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public void main() {
Map peopleMap = new HashMap<>();
People zhangsan = new People("zhangsan", 21);
People zhangsan2 = new People("zhangsan", 21);
peopleMap.put(zhangsan, "zhangsan");
peopleMap.put(zhangsan2, "zhangsan2");
for (Map.Entry entry : peopleMap.entrySet()) {
System.out.println(entry.getKey() + ": " + peopleMap.get(entry.getKey()));
}
}
/*
输出:People{name='zhangsan', age=21}: zhangsan
People{name='zhangsan', age=21}: zhangsan2
分析:本来想等的两个object:o1和o2,o1.hashCode( ) == o2.hashCode( ),但是o1.equals( ) != o2.equals( ),
这时,第一个v1并没有被覆盖,map中实际存了两个key,o1和o2.
*/
五、只实现equals,没实现hashCode
static class People {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age &&
Objects.equals(name, people.name);
}
/*
@Override
public int hashCode() {
return Objects.hash(name, age);
}*/
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public void main() {
Map peopleMap = new HashMap<>();
People zhangsan = new People("zhangsan", 21);
People zhangsan2 = new People("zhangsan", 21);
peopleMap.put(zhangsan, "zhangsan");
peopleMap.put(zhangsan2, "zhangsan2");
for (Map.Entry entry : peopleMap.entrySet()) {
System.out.println(entry.getKey() + ": " + peopleMap.get(entry.getKey()));
}
}
/*
输出:People{name='zhangsan', age=21}: zhangsan
People{name='zhangsan', age=21}: zhangsan2
两个对象虽然相等,但是hashCode返回的值不一样,导致两个对象被存放在了不同的slot中。所以也是存了两个。
*/
当我们实现了equals时,必须要实现hashCode,
https://stackoverflow.com/questions/2265503/why-do-i-need-to-override-the-equals-and-hashcode-methods-in-java