zoukankan      html  css  js  c++  java
  • java中equals和hashCode方法随笔二

    前几天看了篇关于java中equals和hashCode方法的解析

    1、Object类中的equals方法和hashCode方法。

    Object类中的equals和hashCode方法简单明了,所有的类都继承了这两个方法,只是有些类(String、Integer等)会重写这两个方法实现自己的更详细功能,之后会重点介绍。

    ① equals():

    1
    2
    3
    public boolean equals(Object obj) {
            return (this == obj);    
    }
    ②hashCode():
    1
    public native int hashCode();
    1
     
    1
    equals方法比较两个对象的引用(地址)是否相等,hashCode调用的是本地的方法,实质上对象调用hashCode方法返回的是对象引用(地址)的值。这样若equals方法返回为true,这两个引用一定是相等的,hashCode方法返回的值也就是相等的。
    1
      
    1
      
    1
    <SPAN style="FONT-SIZE: medium"><STRONG> 2、其他类中重写的equals方法和hashCode方法。</STRONG></SPAN>
    1
     
    1
    java类库中很多类都重写了Object中的这两个方法,实现了自己更详细的功能,比如String类中重写equals之后,保证了即使对象引用不同,但是字符串的内容相同,也同样返回为true,也被认为是两个字符串对象是相等的,这在语义上也更符合人类的思维.比如:
    1
    2
    3
    4
            String str1 = new String("abc");
    String str2 = new String("abc");
    System.out.println(str1.equals(str2));//返回true
    System.out.println(str1 == str2); //返回false
    1
     
    1
      
    1
    在这段代码中str1 和 str2 是保存的不同的引用的,但是字符串的内容是相同的,都是“abc”(其实“abc”在String类中是以字符数组保存的,喜欢看java源代码,了解类的内部实现的童鞋应该很了解吧,推荐大家在用一个类的时候多看它的源代码,很多实现的原理都可以找到,并且能够学到很棒的类的设计和算法的实现-_-)。使用 == 比较的则是两个地址是否相等,当然返回的是false.但是使用String类中重写的equals方法便能够判断两个对象内部的字符串是相同的,也理所当然的返回true.
    1
      
    1
    下面给出String类中这两个方法的实现:
    1
      
    1
    ①equals():
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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;
        }
    1
    ②hashCode():
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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;
     }
    1
      
    1
    从上面两个方法我们可以了解到很多东西,equals方法首先判断了两个引用是否相等,如果相等直接return true,这是必须的,引用都相等了肯定是同一个对象.如果引用不相等,并没有结束,而是继续判断是不是String类的实例,如果是,检测对象中字符串数组的每一个元素是否相同,如果相同那么就返回true,判定为相等。
    1
      
    1
    在看hashCode方法,String类中也重写了hashCode方法,其中返回一个int型数据,可以看出是根据字符串数组中的元素计算出来的一个值。试想一下,如果equals方法返回为true,那说明这个String对象里面的内容是一样的,hashCode方法根据内容计算的返回的值也当然是相同的了。
    1
      
    1
    不知各位发现了没有,对于equals返回为true的两个对象,hashCode方法返回的值也一定是相同的(对于Object类,equals返回true表示地址相同,hashCode正好是返回地址,必定相同。对于String类,equals返回true表示内容相同,hashCode根据内容返回一个值,也必定是相同的)。
    1
      
    1
    但是反过来成立么,对于hashCode返回值相同的对象,equals返回一定是true吗?思考一下,答案是否定的。因为String类中的hashCode是根据字符数组的元素经过一系列复杂计算得出的,会不会有这种情况,hashCode的返回值相同,但是字符串的内容错位差那么一点(就是字符串的元素不完全相同,但是经过计算恰好保证了hashCode相同),这点概率还是有的。所以上面的那句话是不成立的,这里可能有点难以理解,静下心来仔细想想.
    1
      
    1
    再来一句话,hashCode返回值不同的对象,equals返回一定是false,对否? ……这个通过上面的红字应该可以推理得到吧。hashCode返回不同,但是equals返回为true,可能吗..equals返回为true,hashCode就一定相等了好么亲爱的。所以这句话是对的。
    1
      
    1
    我们还应该注意,Java语言对equals()的要求如下,这些要求是必须遵循的:
    1
      

    • 对称性:如果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方法返回为true的两个对象,一定要保证hashCode返回值相等。Object类中保证了,String类中保证了,大家可以去看Double类,Integer类就会返现,都保证了这一点,hashCode都是与内容有关的。在自己编码设计类的过程中,如果要重写equals方法,进行自己的必要,也要注意同时重写Object的hashCode方法,保证这一点。

    上实例,要求设计一个Student类,重写equals方法和hashCode方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    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)
      
        {
      
            if(this == o)
            {
                return true;
            }
              
            Student s = (Student) o;
      
            return num == s.num && name.equals(s.name);
      
        }
      
        public String toString()
      
        {
      
            return num + ":" + name;
      
        }
      
    }

    看上面这个例子是否能够满足前面谈到的要注意的几点?

    若两个Student对象学号和名字一样能否返回true?

    若equals方法返回true,hashCode返回值是否相等?

    总结:①Object类中有自己的equals和hashCode方法,String等类进行了重写,可以判断内容是否真正相等。

              ②重写equals方法必须同时重写与之相配的hashCode方法。 

              ③equals返回为true的两个对象,hashCode返回的值必须是相同的。

              ④hashCode返回值相同,equals不一定返回true。

              ⑤hashCode返回值不相同,equals一定返回的是false。

    谈到这两个方法不得不提到集合类中Hash那一辈,下一篇博文将详细讲解和理清集合类中是如何通过这两个方法,保证集合中的元素不重复的,会利用hashCode方法和equals方法从内部了解其中比较的技巧.

  • 相关阅读:
    使用git bash提交代码到github托管
    eclipse中将java项目变成web项目
    程序员的兼职网站
    python 文件内容修改替换操作
    简单介绍下python中函数的基础语法
    python lambda简单介绍
    微信小程序 --01
    微信小程序开发 --02
    弹性盒模型flex
    HTML基础
  • 原文地址:https://www.cnblogs.com/shaohz2014/p/3690918.html
Copyright © 2011-2022 走看看