在 Java 中,自定义类是指开发人员自己定义的类,而不是Java语言中内置的类。在自定义类中,如果要将自定义类用作 Map
的键或 Set
的元素,那么必须要重写 equals
方法和 hashCode
方法。
重写 equals
方法和 hashCode
方法是为了保证自定义类的正确性。在 Java 中,Map
和 Set
等容器类使用 equals
方法来比较两个对象是否相等,使用 hashCode
方法来计算对象的哈希值。如果没有重写 equals
方法和 hashCode
方法,那么默认的 equals
方法和 hashCode
方法可能会导致一些问题。
首先,默认的 equals
方法只比较对象的引用,而不是对象的属性值。如果自定义类中有多个属性,这可能会导致一些问题。例如,如果两个对象只有一个属性不同,那么它们的 equals
方法会返回 true
,从而导致 Map
或 Set
中出现重复元素。其次,默认的 hashCode
方法也存在同样的问题。
因此,为了保证自定义类的正确性,必须要重写 equals
方法和 hashCode
方法。在重写 equals
方法和 hashCode
方法时,需要考虑自定义类的所有属性,并返回一个 布尔值 和一个 整数值。
- 示例 1:自定义类中只有单个属性
public class CustomClazz {
private final String key;
public CustomClazz(String key) {
this.key = key;
}
public String getKey() { return key; }
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if ((obj == null) || getClass != obj.getClass()) return false;
return key.equals((CustomClazz) obj.key);
}
@Override
public int hashCode() {
return key.hashCode();
}
}
- 示例2:自定义类中有多个属性
public class CustomClazz {
private final String key1;
private final String key2;
public CustomClazz(String key1, String key2) {
this.key1 = key1;
this.key2 = key2;
}
public String getKey1() { return key1; }
public String getKey2() { return key2; }
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if ((obj == null) || getClass != obj.getClass()) return false;
if (!key1.equals((CustomClazz) obj.key1)) return false;
return key2.equals((CustomClazz) obj.key2);
// 或者直接新建一个临时对象
// CustomClazz that = (CustomClazz) obj;
// if (!key1.equals(that.key1)) return false;
// return key2.equals(that.key2);
}
@Override
public int hashCode() {
int result = key1.hashCode();
result = 31 * result + key2.hashCode();
return result;
}
}
至于为什么在哈希值计算时用到了
31
31
31 这个数,由于本人数学水平实在不咋地,我只能大概的说是因为
31
31
31 是一个不大不小的质数,且可以被 JVM 优化成位移运算,即 31 * i = (i << 5) -i
,想要深入探究,建议百度 😝