JAVA中判断对象是否相等按如下规则:
首先,判断两个对象的hashCode是否相等
如果hashcode不相等,认为两个对象也不相等
如果hashcode相等,则需进一步判断equals运算是否相等
如果equals运算不相等,认为两个对象也不相等
如果equals运算相等,认为两个对象相等
要注意的是equals()和hashcode()这两个方法都是从object类中继承过来的,Object类中,hashcode方法返回值是如何得到请查阅其他文献,equals方法相当于==,是比较对象的引用值是否相等。
public boolean equals(Object obj) { return (this == obj); }
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; }
• 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
• 反射性:x.equals(x)必须返回是“true”。
• 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
• 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
• 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31 * h + val[off++]; } hash = h; } return h; }
equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。
public static void main(String args[]){ String s1=new String("pstar"); String s2=new String("pstar"); System.out.println(s1==s2);//false System.out.println(s1.equals(s2));//true System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode() System.out.println(s2.hashCode()); Set hashset=new HashSet(); hashset.add(s1); hashset.add(s2); Iterator it=hashset.iterator(); while(it.hasNext()){ System.out.println(it.next()); } }
false true -967303459 -967303459
public class HashSetTest { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add(new Student(1, "zhangsan")); hs.add(new Student(2, "lisi")); hs.add(new Student(3, "wangwu")); hs.add(new Student(1, "zhangsan")); Iterator it = hs.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } class Student { int num; String name; Student(int num, String name) { this.num = num; this.name = name; } public String toString() { return num + ":" + name; } }
1:zhangsan 1:zhangsan 3:wangwu 2:lisi
那么怎么解决这个问题呢?答案是:在Student类中重新hashcode()和equals()方法。
例如:
class Student { int num; String name; Student(int num, String name) { this.num = num; this.name = name; } public int hashCode() { return num * name.hashCode(); } public boolean equals(Object o) { Student s = (Student) o; return num == s.num && name.equals(s.name); } public String toString() { return num + ":" + name; } }
1:zhangsan 3:wangwu 2:lisi
1) 重点是重写equals,重写hashCode只是为了提高效率
2) 为什么重点是重写equals呢,因为比较对象相等最终是靠equals来判断
3)hash函数性能高,所以重写hashcode方法在equals方法之前先过滤一次,会加速比较过程