关于重写hashcode和equals方法的理解
为什么要重写equals方法
谈一下自己的理解, 当我们新建对象, 比较两个对象是否相同时, 默认使用的是Object的equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
双等号:
基本数据类型比较的是值是否相等
引用数据类型比较的是对象的地址值是否相等
所以对于新创建的对象来说, 想要判断对象的值是否相等, 一般要重写equals方法.
为什么要重写hashcode方法
object 的hashcode方法
public native int hashCode();
然后我们再了解一下hashCode 的常规协定:
- 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
- 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
- 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
个人认为重写hashcode方法有以下几个原因:
- 重写equals方法, 通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
- 有利于提高equals方法的效率(先判断hashcode是否相同, 若不相同, 则对象一定不同)
- 当使用到一些特殊的类, 特殊的方法时, 一定要重写hashcode 方法, 否则会出现问题, 例如:Hashtable类中的get(Object key) 和 put(K key, V value) 方法
public Object put(Object key, Object value) {
// Make sure the value is not null
if (value == null) throw new NullPointerException();
// Makes sure the key is not already in the hashtable.
HashtableEntry e;
HashtableEntry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
Object old = e.value;
e.value = value;
return old;
}
}
// Rehash the table if the threshold is exceeded
if (count >= threshold) {
rehash();
return put(key, value);
}
// Creates the new entry.
e = new HashtableEntry();
e.hash = hash;
e.key = key;
e.value = value;
e.next = tab[index];
tab[index] = e;
count++;
return null;
}
由于Hashtable 使用的是哈希表结构, 存值的时候需要根据key的hash值取余作索引, 所以当使用的put(K key, V value) 方法的key为没有重写hashcode方法和equals方法(由于该方法中调用了该对象的equals方法)的对象时, 就会产生问题:
- 使用 put(K key, V value) 方法时, 相同key值的对象可能无法覆盖, 而是重新创建
- 使用get(key)方法可能无法获取对应的value
例如:
没有重写hashcode和equals方法
重写后:
所以为了避免不必要的问题, 还是建议重写hashcode方法, 毕竟都是自动代码生成, 很方便