zoukankan      html  css  js  c++  java
  • 重写equals,为什么要重写hashcode()

    解释得很清楚!为什么重写equals()方法必须重写hashcode()方法?

    程序猿的内心独白

    发布时间:02-2212:02

    今天来点比较基础的。

    equals方法是Object类的方法,比较的是地址是否相等,跟==是等价的,注意,这说的是Object中是等价的。

    public boolean equals(Object obj) { return (this == obj); }

    但是,往往我们会重写这个方法,比如判断字符串是否相等啦

    所以String重写了equals()方法:

    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;

    }

    可以看到比较的字符串内容是否相等,而不是地址了

    再看hashcode方法也是object的方法,是一个native方法,看不到源码,但是根据注释可以知道它是根据对象的地址来算的,那么不同对象的hashcode就不一样了(极大的概率)

    那为什么重写equals就要重写hashcode呢?

    假设String只重写了equals、没重写hashcode,即 下边的ss1.equals(ss2)是true但是二者的hashcode不相等(地址不同)

    String ss1="mayijinfu";

    String ss2="mayijinfu";

    现在我们在hashset插ss1和ss2,hashset会:

    判断插入的值的hashcode存不存在,插ss1判断不存在,把ss1插入

    插ss2判断还是不存在(ss1,ss2的hashcode不相等,所以set不知道他两的值一样),这样ss2也被插入了

    这时我们遍历set会发现存在两个mayijinfu,这不就乱套了吗。

    归根到底 很多容器先根据hashcode判断存不存在如果hashcode存在再去根据equals判断,

    因为hashcode大概率不相等,所以可以少判断一步equals

    如果先判断equals,大概率是不相等的,还要在判断hashcode

    所以我们重写hashcode,不再根据地址来生成hashcode,而是根据我们自己规定的规则,比如上边ss1和ss2,只要内容一样我们就让他的hashcode一样(String就是这么办的)

    当我们重写完hashcode后,ss1和ss2的hashcode就相等了,

    现在我们在hashset插ss1和ss2,hashset会:

    判断插入的值的hashcode存不存在,插ss1时判断这个hashcode不存在,把ss1插入

    插ss2判断它的hashcode存不存在,因为我们重写了hashcode,所以已经存在了(ss1,ss2的hashcode相等,所以set知道了两的值可能一样),因为hashcode一样了,set会再去进一步用equals判断,ss1.equals(ss2) 返回true,那确定无疑他两是同一个东西了(在我们的规则下)。

    再来一个string的例子:

    String的==比的是地址,地址相同才true;

    String的equals()比的是每个字符;

    String ss1="mayijinfu";

    String ss2="mayijinfu";

    String sn1= new String("mayijinfu");

    String sn2=new String("mayijinfu");

    System.out.println("ss1==ss2:"+(ss1==ss2));

    System.out.println("ss1==sn1:"+(ss1==sn1));

    System.out.println("sn1==sn2:"+(sn1==sn2));

    System.out.println("ss1.equals(ss2):"+ss1.equals(ss2));

    System.out.println("ss1.equals(sn1):"+ss1.equals(sn1));

    System.out.println("sn1.equals(sn2):"+sn1.equals(sn2));

    输出结果:

    ss1ss2:true

    ss1sn1:false

    sn1==sn2:false

    ss1.equals(ss2):true

    ss1.equals(sn1):true

    sn1.equals(sn2):true

    接下来举一个例子:hashcode相同,但是内容不同 (真的存在)

    下边代码中,p1和p2的hashcode相同,但是打印结果为true,false,"no boundaries",null,也就是通过p2得不到p1的value,为啥呢?不是说Hashmap散列的时候看hashcode吗?

    计算索引是根据hashcode来算的,但是equals同样要用到的。

    String p1="儿女";

    String p2 = "农丰";

    HashMap<String,String> map = new HashMap<>();

    map.put(p1,"no boundaries");

    System.out.println("p1.hashCode()==p2.hashCode()"+(p1.hashCode()==p2.hashCode()));

    System.out.println("p1.equals(p2)"+p1.equals(p2));

    System.out.println("map.get(p1)"+map.get(p1));

    System.out.println("map.get(p2)"+map.get(p2));

    hashmap的get方法依赖equals方法,上边p1.equals(p2)是false,所以get到的是null啦。所以你想通过p2来get到p1的value,只能重写equals方法,但是问题又来了,String是final类,所以你只能定义别的类了。

    先定义一个类pp,然后重写hashcode()和equals()方法,这里hashcode其实就是他们值的hashcode,也就是String里的hashcode,所以"儿女"和"农丰"的hashcode还是一样的,然后我让equals()方法的返回值跟hashcode()的返回值一致。

    class pp {

    String s;

    public pp(String s){

    this.s = s;

    }

    @Override

    public boolean equals(Object obj){

    return s.hashCode()==obj.hashCode();

    }

    @Override

    public int hashCode(){

    return s.hashCode();

    }

    }

    java

    pp p1 = new pp("儿女");

    pp p2 = new pp("农丰");

    HashMap<pp,String> map = new HashMap<>();

    map.put(p1,"nb");

    System.out.println("p1.hashCode()==p2.hashCode()"+(p1.hashCode()==p2.hashCode()));

    System.out.println("p1.equals(p2)"+p1.equals(p2));

    System.out.println("map.get(p1)"+map.get(p1));

    System.out.println("map.get(p2)"+map.get(p2));

    这样的话,p1和p2不光hashcode()相等,equals()也相等了,所以执行map.get(p2)得到的就是p1的value了。打印结果

    p1.hashCode()==p2.hashCode()true

    p1.equals(p2)true

    map.get(p1)no boundaries

    map.get(p2)no boundaries

    转载:https://baijiahao.baidu.com/s?id=1659208076366376304&wfr=spider&for=pc

  • 相关阅读:
    charles抓包实战
    linux环境安装jdk
    excel单元格数据变#号解决办法
    搭建接口自动化框架(附源码)
    dos批处理学习
    python远程操作linux服务器(获取ip,执行多条linux命令,上传文件)
    jmeter(五)创建web测试计划
    转载jmeter(四)配置元件
    JMeter(三)页面和主要测试组件
    jmeter(二)jmeter的目录解析
  • 原文地址:https://www.cnblogs.com/w123w/p/13575711.html
Copyright © 2011-2022 走看看