Java中,涉及到两个对象的比较时,我们会用到hashCode()和equals()。这两个方法是Object类中定义的方法。
1. api中的描述
(1)hashCode()
hashCode()方法给对象返回一个hash code值。这个方法被用于hash tables,例如HashMap。
它的性质是:
- 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个integer。
- 如果两个对象根据equals(Object)方法是相等的,那么调用二者各自的hashCode()方法必须产生同一个integer结果。
- 并不要求根据equals(java.lang.Object)方法不相等的两个对象,调用二者各自的hashCode()方法必须产生不同的integer结果。然而,程序员应该意识到对于不同的对象产生不同的integer结果,有可能会提高hash table的性能。
大量的实践表明,由Object类定义的hashCode()方法对于不同的对象返回不同的integer。
(2)equals()
equals()进行的内容比较,而已经不再是地址的比较。依次类推Math、Integer、Double等这些类都是重写了equals()方法的,从而进行的是内容的比较。当然,基本类型是进行值的比较。
它的性质有:
- 自反性(reflexive)。对于任意不为null的引用值x,x.equals(x)一定是true。
- 对称性(symmetric)。对于任意不为null的引用值x和y,当且仅当x.equals(y)是true时,y.equals(x)也是true。
- 传递性(transitive)。对于任意不为null的引用值x、y和z,如果x.equals(y)是true,同时y.equals(z)是true,那么x.equals(z)一定是true。
- 一致性(consistent)。对于任意不为null的引用值x和y,如果用于equals比较的对象信息没有被修改的话,多次调用时x.equals(y)要么一致地返回true要么一致地返回false。
- 对于任意不为null的引用值x,x.equals(null)返回false。
对于Object类来说,equals()方法在对象上实现的是差别可能性最大的等价关系,即,对于任意非null的引用值x和y,当且仅当x和y引用的是同一个对象,该方法才会返回true。
需要注意的是当equals()方法被override时,hashCode()也要被override。按照一般hashCode()方法的实现来说,相等的对象,它们的hash code一定相等。
2. 总结
在Object类中,未覆盖的hashcode()方法产生的hashcode, 可标识该对象在hash表中位置。
由于hash表可能会产生hash冲突,所以hashCode相同的对象不一等相等。
在Object类中,未覆盖的equals方法,使用“==”进行比较的,比较的是两个对象的地址是否相同。
如果两个对象equals比较为真,即两个对象相等,则两个对象的hashcode一定相同;反过来,两个对象的hashcode相同,不代表两个对象相同(有可能hash冲突),equals比较不一定为真
在hashset 或者hashMap中,新加入一个对象的时候,它会使用对象的HashCode()值来判断对象加入的位置,但同时也会与其他的已经加入的对象的HashCode作对比,如果没有相符的hashcode,Hahset或者HashMap就会假设新对象没有重复出现。如果HashCode()相同,接下来才会比较两个对象是否真正相同。
采用这种先比较hashcode才比较是否相等的方式,可以极大地提高hashset,hashmap查找插入的效率。(时间复杂度为O(1))
3.覆盖Object类的hashCode()和equals()方法
我们可以根据自己的需要来覆盖Object类中的hashCode()和equals()方法。
例如String中的hashcode()和equals()方法
/**
* Returns a hash code for this string. The hash code for a
* <code>String</code> object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using <code>int</code> arithmetic, where <code>s[i]</code> is the
* <i>i</i>th character of the string, <code>n</code> is the length of
* the string, and <code>^</code> indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}