SO面试题07:使用equlas和hashcode方法时,我们需要考虑那些问题?
# 问题
当我们使用equals和hashcode方法时,我们需要考虑什么问题?
# 最佳答案
就像《effective java》这本书中提到,尽管java.lang.Object是一个具体的类,但是这个类的主要功能就是用于扩展(非final方法可被覆盖),因此,它所有的非final方法都有明确的约定。所有的类在覆盖Object的方式时,都有义务遵守这些约定。否则,其它依赖这些约定的类就无法正常运转,比如我们经常提到的HashMap、HashSet等等。
接着,咱们看看本题目中所提到的两个方法:
hashCode()
我们可以主要到这个方法由native关键字修饰,因此,它底层由c/c++来实现(符合JNI编程规范),关于具体的实现,这里不做过多的讨论,感兴趣的可以去看看openjdk源码。
同时,javadoc文档中提到:如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个integer。
equals()
从Object的源码中,我们可以看出它是对两个对象的地址值进行的比较(即比较引用是否相同)。如果你看过String 、Math、Integer、Double等这些包装类的equals()方法源码时,会发现,它们已经覆盖了object类的equals()方法。
它们已不再符合地址比较,它们之间符合等价关系(自反性,对等性,传递性,一致性),另外,它们必须是一致的(如果未修改对象,则它必须保持返回相同的值)。此外,o.equals(null)必须始终返回false。
因此,这两个方法之间的关系,应该是:
如果两个对象相同,那么它们的hashCode值一定要相同;
如果两个对象的hashCode相同,它们并不一定相同(这里说的对象相同指的是用eqauls方法比较)。
equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。
Object规范
这里需要再次提醒一下,也是在《effective java》这本书(见第9条)中曾提到过,也是本题的答案:equal和hashcode方法必须同时重写,缺一不可。
怎么重写呢?
使用类的同组属性去重写equals和hashcode方法。
这里,第三方的组件commons-lang3给我们提供了两个工具类,分别是 EqualsBuilder 和 HashCodeBuilder方法,见下面的例子:
public class Person {
private String name;
private int age;
// ...
@Override
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
记住,使用基于hashcode的Collection或Map(例如HashSet,LinkedHashSet,HashMap,Hashtable或WeakHashMap)时,请确保放入元素(key)的hashcode在集合中一直保持不变。
我记得之前有个同学,跟我提过,他在使用hibernate的过程中,发现hibernate经常会使用set集合来保持相关对象。他有次只重写了equals方法,而没有重写hashcode方法,当存入的元素越来越多时,发现性能越来越差,为啥呢?
后来,跟踪发现,原来是set在进行判重时,会有大量的元素的hashcode方法返回的值一样,因此会调用equals方法进行比较,降低了性能。重写了hashcode方法,就好了。
比如,这样写:
public int hashCode(){
return 1; //等价于hashcode无效
}
你可以去尝试一下。
今晚,就写到这里,记得转发,给我补充下一直写下去的燃料~~~
参考:http : //stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java
往期推荐
🔗
点击阅读原文,获得更多精彩内容