基本概念
== 是运算符, 比较的是两个变量是否相等;
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];
来源: https://www.cnblogs.com/yizhiamumu/p/9134720.html