基本概念
- ==是运算符,比较的是两个变量是否相等;
- equals()是Object方法,用于比较两个对象是否相等
看一下源码:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
当this==anObject的时候,返回true,即this 和 obj引用同一个对象时,才会返回true;
还有就是当判断字符串相等的时候,当anObject是String类型,并且长度和内容一样的时候,返回true;
小结
只有当引用一个对象的时候,才会返回true。
而我们在实际用equals()方法的时候,我们往往不是为了判断两个引用的是一个对象,因此我们此时要重写equals()方法;
equals()有以下的公约必须遵守:
- 对称性:x,y非空,如果x.equals(y)返回true,那么y.equals(x)必为true;
- 自反性:对于任何非null的引用值x,x.equals(x)必须返回true;
- 传递性:x,y,z非空,x.equals(y),y.equals(z)返回true,那么x.equals(z)必为true;
- 一致性:x,y非空,只要对象信息没有被修改,那么多次调用x.equals(y)的结果肯定都一样;
- 对于任何非null的引用值x,x.equals(null)必须返回false;
因此,我们一般有以下推论:
- 任何情况下,x.equals(null),永远返回是false;x.equals(和x不同类型的对象)永远返回是false。
- equals()相等的两个对象,hashcode()一定相等;反过来:hashcode()不等,一定能推出equals()也不等;
- hashcode()相等,equals()可能相等,也可能不等
现在我们可以这样解释了:
1、因为是按照hashCode来访问小内存块,所以hashCode必须相等。
2、HashMap获取一个对象是比较key的hashCode相等和equal为true。
3、比如对象ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。所以hashCode相等,却可以equal不等
当我们编写完成了equals()方法的时候,我们要问自己三个问题:它是否是对称的、传递的、一致的;
问题:重写equals()方法的时候总要重写hashcode()方法,为什么要重载equal方法?
在每个重写equals()的类中,我们必须重写hashcode()方法;如果不这样做,会违反hashcode()的公约:
- 1.只要对象的信息没有改变,那么对一个对象调用多次,hashcode()方法都必须始终如一的返回同一个整数;
- 2.如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashcode()方法都必须产生同样的结果;
- 3.如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashcode()方法不一定产生同样的结果;
相等的对象必须有相同的散列码
代码示例
import java.util.HashSet; import java.util.Set; /** * hashcode和equals方法 * HashMap中有一个put方法,put(key,value)key是无序不可重复的 */ public class SetTest2 { public static void main(String[] args) { //创建集合 Set es = new HashSet(); Employee e1 = new Employee("1000","tao"); Employee e2 = new Employee("1000","tao"); // Employee e2 = new Employee("1001","tao1"); Employee e3 = new Employee("1002","tao2"); Employee e4 = new Employee("1003","tao3"); Employee e5 = new Employee("1004","tao4"); Employee e6 = new Employee("1005","tao5"); // System.out.println(e1.equals(e2)); // System.out.println(e2); System.out.println(e1.hashCode()); System.out.println(e2.hashCode()); es.add(e1); es.add(e2); es.add(e3); es.add(e4); es.add(e5); es.add(e6); System.out.println(es.size()); } } class Employee{ String num;//员工编号 String name; Employee(String num,String name){ this.num = num; this.name = name; } //重写equals方法,如果员工编号相同并且名字相同,则是同一个对象 public boolean equals(Object o){ if (this == o){ return true; } if (o instanceof Employee){ Employee e = (Employee) o; if (e.num.equals(this.num) && e.name.equals(this.name)) { return true; } } return false; } //重写Hashcode方法 public int hashCode(){ //以员工编号分组,可散列均匀分布 return num.hashCode(); } } hashCode()的底层实现: public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
可以看到最终hash = s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1];