重写equals方法不重写hashcode方法分析

本文深入探讨了Java中equals和hashCode方法的实现原理,强调了重写这些方法时需遵循的规则,包括自反性、对称性、传递性和一致性,并通过具体示例展示了如何正确重写equals和hashCode方法,以确保对象比较的正确性和散列表性能的提升。
摘要由CSDN通过智能技术生成

equals源码:

 public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }
 public boolean equals(Object obj) {
        return (this == obj);
    }

可见,源码中的equals不重写的话,就是==

先重写equals方法:

加入有一个user类,忽略掉id属性,比较name和age,如果两个相等,则视为true。

重写equals方法需要遵循Java如下规则,否则编码行为会难以揣测:
  • 自反性:对于任意的对象x,x.equals(x)返回true(自己一定等于自己);
  • 对称性:对于任意的对象x和y,若x.equals(y)为true,则y.equals(x)亦为true;
  • 传递性:对于任意的对象x、y和z,若x.equals(y)为true且y.equals(z)也为true,则x.equals(z)亦为true;
  • 一致性:对于任意的对象x和y,x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也均为true,前提条件是没有修改x也没有修改y;
  • 对于非空引用x,x.equals(null)永远返回为false。
写一下单元测试:
public class userTest {

    @Test
    public void equals1() {
        user x = new user(0,"刘三",18);
        user y = new user(4,"刘三",18);
        user z = new user(0,"刘三",18);
	/** 自反性:对于任意的对象x,x.equals(x)返回true(自己一定等于自己);*/
	  assertTrue(x.equals(x));
	  /** 对称性:对于任意的对象x和y,若x.equals(y)为true,则y.equals(x)亦为true;*/
        assertTrue(x.equals(y));
        assertTrue(y.equals(x));

	/**
        传递性:对于任意的对象x、y和z,若x.equals(y)为true且y.equals(z)也为true,则x.equals(z)亦为true;*/
        assertTrue(x.equals(y));
        assertTrue(y.equals(z));
        assertTrue(x.equals(y));
/**
        一致性:对于任意的对象x和y,x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也均为true,前提条件是没有修改x也没有修改y;*/
        assertTrue(x.equals(y));

/**
        对于非空引用x,x.equals(null)永远返回为false。*/
        assertFalse(x.equals(null));
       
    }
}

代码

public class user {
 private  int id;
 private  String name;
 private  int age;

   user(int id,String name,int age){
       this.id =id;
       this.name=name;
       this.age =age;
   }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        user user = (user) o;
        return 
                age == user.age &&
                Objects.equals(name, user.name);
    }
}

hashcode 方法的通用约定

  • 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一地返回 同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
  • 如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。
  • 如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
单元测试代码
/* -  在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,
       它必须始终如一地返回 同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,
       即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
        */
       assertTrue(x.hashCode()==x.hashCode()&&x.hashCode()==x.hashCode());
       /*- 如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。*/
        assertFalse(x.hashCode()==z.hashCode());
        assertFalse(x.hashCode()==y.hashCode());
       /* - 如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,
       不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,
       有可能提高散列表(hash table)的性能。
       */ 

运行通过,发现不满足第二条。即两个相等的对象,hashcode不一样。

再看如下代码片段

HashMap<user,Integer> m = new HashMap<user,Integer>();
              m.put(x,10);
              m.put(y,20);
              m.put(z,30);
        System.out.println(m.get(new user(0,"刘三",18)));

运行结果是null;

  • map 中源码
 public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
get中比较的是hashcode。
而hashcode不相等。

重写hashCode()

 @Override
    public int hashCode() {
        int result = 17;
        result = 31*result + name!=null?name.hashCode():0;
        result = 31*result + age;
        return Objects.hash(name, age);
    }

满足第二条,且System.out.println(m.get(new user(0,“刘三”,18)));的输出为30

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值