转自:/u012767369/article/details/79362752
()方法和hashcode()方法两者关系——hashCode方法设计原则
1) 如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同;
2) 如果两个对象不同(即用equals比较返回false),那么它们的hashCode值可能相同也可能不同;
3) 如果两个对象的hashCode相同(存在哈希冲突),那么它们可能相同也可能不同(即equals比较可能是false也可能是true)
4) 如果两个对象的hashCode不同,那么他们肯定不同(即用equals比较返回false)
hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
2.重写equals()方法——伪代码
1)自反性:(A)要返回true
2)对称性:如果(B)返回true,那么(A)也要返回true
3)传递性:如果(B)返回true,(C)为true, 则(C)也要为true. 说白了就是 A = B , B = C , 那么A = C.
4)一致性:只要A,B对象的状态没有改变,(B)必须始终返回true.
5)(null) 要返回false.
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
3.重写equals()方法——具体步骤分为两步,先重写equals()方法,后重写hashCode()方法
重写equals()方法
示例类
class Coder{
private String name;
private int age;
}
因为默认的equals()实际是判断两个引用是否指向内在中的同一个对象,相当于==,具体遵循以下三个步骤
1)判断是否等于自身
if(otherr == this)
return true;
2)使用instanceof运算符判断other是否为Coder类型的对象
if(!(other instanceof Coder))
return false;
3)比较Coder类中你自定义的数据域,name和age,一个都不能少
Coder o = (Coder)other;
return (name) && == age;
注意:第3步中有一个强制转换,如果有人将一个Integer类的对象传到了这个equals中,那么会不会扔ClassCastException呢?这个担心其实是多余的.因为我们在第二步中已经进行了instanceof 的判断,如果other是非Coder对象,甚至other是个null, 那么在这一步中都会直接返回false, 从而后面的代码得不到执行的机会,上面的三步也是<Effective Java>中推荐的步骤,基本可保证万无一失
重写hashcode()方法
重写了equals()方法一定要重新hashcode方法,重写时要注意保证Coder对象的所有成员都能在hashCode中得到体现(关键)
@Override
public int hashCode(){
int result = 17;
result = result * 31 + ();
result = result * 31 + age;
return result;
}
PS:String中hashCode()的实现是 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
可以看出是对每个字符的ASCII码计算n-1次方后再进行求和,可以最大程度上避免2个不同的String会出现相同的hashCode的情况,至于为什么选择31,感兴趣可以看看这个:/nullllun/p/
4.重写equals()方法而不重写hashCode()方法的风险
Java中通过hashCode()方法来确定一个对象应该位于哪个bucket中,然后在相应的链表中进行查找,在理想的情况下,如果你的hashCode()方法足够健壮,那么每个bucket将会只有一个节点,这样实现了查询操作的常量级别的时间复杂度。一旦你重写了equals()方法,但是没有重写hashCode()方法,那么equals返回为true的对象会因为hashCode不同而放在不同的bucket中,而理论上应该是放在一个bucket中的,同时在进行查询的时候,也会因为定位到不同的位桶而找不到指定的元素(equals为true的目标对象)。因此,重写hashCode的原因是,在(B)返回true的情况下,A,B的hashCode()要返回相同的值。
PS:hashCode()是为哈希表服务的,用于快速定位元素在数组中的位置,不能让hashCode()方法每次都返回一个固定的数,这样的话hashMap和hashSet就失去了意义,哈希表就退化成了链表,每次查询都只是遍历链表,完全失去了hash的作用
copy from:/u012767369/article/details/79362752
_________________________________________________
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == ) {
char v1[] = value;
char v2[] = ;
int i = offset;
int j = ;
while (n– != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Math、Integer、Double等这些类都是重写了equals()方法的,从而进行的是内容的比较。当然,基本类型是进行值的比较。
它的性质有:
- 自反性(reflexive)。对于任意不为
null
的引用值x,(x)
一定是true
。 - 对称性(symmetric)。对于任意不为
null
的引用值x
和y
,当且仅当(y)
是true
时,(x)
也是true
。 - 传递性(transitive)。对于任意不为
null
的引用值x
、y
和z
,如果(y)
是true
,同时(z)
是true
,那么(z)
一定是true
。 - 一致性(consistent)。对于任意不为
null
的引用值x
和y
,如果用于equals比较的对象信息没有被修改的话,多次调用时(y)
要么一致地返回true
要么一致地返回false
。 - 对于任意不为
null
的引用值x
,(null)
返回false
。
对于Object
类来说,equals()
方法在对象上实现的是差别可能性最大的等价关系,即,对于任意非null
的引用值x
和y
,当且仅当x
和y
引用的是同一个对象,该方法才会返回true
。
需要注意的是当equals()方法被override时,hashCode()也要被override。按照一般hashCode()方法的实现来说,相等的对象,它们的hash code一定相等。
hashcode() 方法详解
hashCode()
方法给对象返回一个hash code值。这个方法被用于hash tables,例如HashMap。
它的性质是:
- 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用
hashCode()
方法,该方法必须始终如一返回同一个integer。 - 如果两个对象根据
equals(Object)
方法是相等的,那么调用二者各自的hashCode()
方法必须产生同一个integer结果。 - 并不要求根据
equals()
方法不相等的两个对象,调用二者各自的hashCode()
方法必须产生不同的integer结果。然而,程序员应该意识到对于不同的对象产生不同的integer结果,有可能会提高hash table的性能。