zoukankan      html  css  js  c++  java
  • Java的重写equals但不重写hashCode方法的影响

      首先,说下equals和hashCode的关系。JDK API中关于Object类的equals和hashCode方法中说过,总结起来就是两句话:equals相等的两个对象的hashCode也一定相等,但hashCode相等的两个对象不一定equals相等。

      hashCode类似于一个位置值(不叫地址值,是想把每个对象所在的位置做地址值),HashSet、HashMap等集合类中常会用到。

                      

      上图中假设是对象在内存中的模型,则7—c就是位置值即hashCode,而71—74就是地址值。所以x,y和z的hashCode是一样的,但是x、y和z的equals不一定相等,equals相等只跟自己类定义的equals方法有关,加设备x是A类的对象,y类是B类对象,z是C类对象,A、B和C的equals都实现为始终返回true,则程序会认为x、y和z是相等的,若都实现为返回false,则x跟自己都不相等。即equals相等依据的是equals方法。

      当我们重写equals方法时,是有要求的(具体见JDK)。如果只重写了equals,不重写hashCode会有什么影响呢?

      假如该类不会放在HashSet等散列表相关的集合类中,不一定会有影响,如下代码:

    Model类

      1 package com.guanmu.test;
      2 
      3 
      4 /**
      5  * <p>
      6  * 类描述:
      7  * <p>
      8  * 
      9  * 所属插件:com.guanmu.test
     10  * 
     11  * @author guanmu 2015-10-20
     12  * 
     13  */
     14 public class Model {
     15 
     16     private String name;
     17     private String age;
     18     private String otherName;
     19 
     20     /**
     21      * @param name
     22      * @param age
     23      * @param otherName
     24      */
     25     public Model(String name, String age, String otherName) {
     26         super();
     27         this.name = name;
     28         this.age = age;
     29         this.otherName = otherName;
     30     }
     31 
     32     /**
     33      * @return the name
     34      */
     35     public String getName() {
     36         return name;
     37     }
     38 
     39     /**
     40      * @param name
     41      *            the name to set
     42      */
     43     public void setName(String name) {
     44         this.name = name;
     45     }
     46 
     47     /**
     48      * @return the age
     49      */
     50     public String getAge() {
     51         return age;
     52     }
     53 
     54     /**
     55      * @param age
     56      *            the age to set
     57      */
     58     public void setAge(String age) {
     59         this.age = age;
     60     }
     61 
     62     /**
     63      * @return the otherName
     64      */
     65     public String getOtherName() {
     66         return otherName;
     67     }
     68 
     69     /**
     70      * @param otherName
     71      *            the otherName to set
     72      */
     73     public void setOtherName(String otherName) {
     74         this.otherName = otherName;
     75     }
     76 
     77     @Override
     78     public int hashCode() {
     79         
     80         int a = 7;
     81         int b = 11;
     82         // a和b为不相等的int型常量
     83         int r = a;
     84         r = r*b + name.hashCode();
     85         r = r*b + age.hashCode();
     86         
     87 //        return r;
     88         return super.hashCode();
     89     }
     90     
     91     @Override
     92     public boolean equals(Object obj) {
     93         if (!(obj instanceof Model)) {
     94             return false;
     95         }
     96 
     97         Model other = (Model) obj;
     98         if (name.equals(other.getName()) && age.equals(other.getAge())) {
     99             return true;
    100         }
    101 
    102         return false;
    103     }
    104 
    105     /* (non-Javadoc)
    106      * @see java.lang.Object#toString()
    107      */
    108     @Override
    109     public String toString() {
    110         return "Model [name=" + name + ", age=" + age + ", otherName=" + otherName + "]";
    111     }
    112     
    113     
    114 }
    View Code

    测试类

     1 package com.guanmu.test;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashSet;
     5 import java.util.List;
     6 import java.util.Set;
     7 
     8 /**
     9  * <p>
    10  * 类描述:
    11  * <p>
    12  * 
    13  * 所属插件:com.guanmu.test
    14  * @author guanmu2015-10-20
    15  * 
    16  */
    17 public class EqualsTest {
    18     
    19 
    20     
    21     public static void main(String[] args) {
    22         test1();
    23         test2();
    24     }
    25     
    26     public static void test1() {
    27         System.out.println("####:test1");
    28         List<Model> list = new ArrayList<Model>();
    29         
    30         Model a = new Model("a", "20", "test");
    31         Model b = new Model("a","20","abcdef");
    32         Model c = new Model("a","20","");
    33         
    34         list.add(a);
    35         System.out.println("a-hashCode:" + a.hashCode());
    36         System.out.println(list);
    37         if (!list.contains(b)) {
    38             list.add(b);
    39             System.out.println("b-hc:" + b.hashCode());
    40             System.out.println(list);
    41         }
    42         
    43     }
    44     
    45     public static void test2() {
    46         System.out.println("####:test2");
    47         Set<Model> set = new HashSet<Model>();
    48         
    49         Model a = new Model("a", "20", "test");
    50         Model b = new Model("a","20","abcdef");
    51         Model c = new Model("a","20","");
    52         
    53         set.add(a);
    54         System.out.println("a-hashCode:" + a.hashCode());
    55         System.out.println(set);
    56         if (!set.contains(b)) {
    57             set.add(b);
    58             System.out.println("b-hc:" + b.hashCode());
    59             System.out.println(set);
    60         }
    61         
    62     }
    63 }
    View Code

    结果打印如下:

    ####:test1
    a-hashCode:18923308
    [Model [name=a, age=20, otherName=test]]
    ####:test2
    a-hashCode:15136722
    [Model [name=a, age=20, otherName=test]]
    b-hc:26752749
    [Model [name=a, age=20, otherName=test], Model [name=a, age=20, otherName=abcdef]]

      list中能判断出包含了等价的b,但set中认为a和b不相等,set中没有包含b。发现test1()中,ArrayList是根据equals来判断是后包含,而不管hashCode是否不相等。而test2()中,HashSet处理流程则不一样,先判断两个对象的hashCode方法是否一样,如果不一样,立即认为两个对象equals不相等,并不调用equals方法,当hashCode相等时,再根据equals方法判断两个对象是否相等。

      总结,所以当我们缩写的类可能用于存放在Hash相关的集合类中时,在重写equals时,需要重写hashCode,不然会出现与预期不符的结果。从网上搜索了下如何重写hashCode方法,以下据说是《Think in Java》中提到的方法。

        @Override
        public int hashCode() {
            
            int a = 7;
            int b = 11;
            // a和b为不相等的int型常量
            int r = a;
            r = r*b + name.hashCode();
            r = r*b + age.hashCode();
            
            return r;
        }

    其中a和b可以为任意不相等常量。

     

    每多学一点知识,就少写一行代码。
  • 相关阅读:
    为什么要使用href=”javascript:void(0);”
    29zTree
    js获取下拉框的值
    C# 判断文件夹与文件是否存在
    C# 判断文件和文件夹是否存在并创建
    ASP.NET实现excel导入数据库
    同时向主表和从表里面导入execl数据 (asp.net webform)
    EasyUI数据分页实现(真假分页)
    easyui datagrid 前台分页的实现java采用的版本
    异步和多线程
  • 原文地址:https://www.cnblogs.com/guanmu/p/4894430.html
Copyright © 2011-2022 走看看