zoukankan      html  css  js  c++  java
  • 重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述方法

    下面给出一个实例,重新编写equals()方法,提供自定义的相等标准

     1 public class PersonTest {
     2     public static void main(String[] args) {
     3         Person p1 = new Person("孙悟空", "1234");
     4         Person p2 = new Person("孙行者", "1234");
     5         Person p3 = new Person("孙大圣", "12345");
     6         System.out.println("p1和p2是否相等?" + p1.equals(p2));
     7         System.out.println("p1和p3是否相等?" + p1.equals(p3));
     8         System.out.println("p2和p3是否相等?" + p2.equals(p3));
     9     }
    10 }
    11 
    12 class Person {
    13     private String name;
    14     private String id;
    15 
    16     public Person() {
    17     }
    18     public Person(String name, String id) {
    19         this.name = name;
    20         this.id = id;
    21     }
    22 
    23     public String getId() {
    24         return this.id;
    25     }
    26     public boolean equals(Object obj) {
    27         //如果两个对象为同一个对象
    28         if( this == obj) {
    29             return true;
    30         }
    31         //当obj不为null,其它是Person类的实例时
    32         if( obj != null && obj.getClass() == Person.class) {
    33             Person obj2 = (Person)obj;
    34             //并且当前对象的id与obj对象的id相等才可判断两个对象相等
    35             if (this.getId().equals(obj2.getId())) {
    36                 return true;
    37             }
    38         }
    39         return false;
    40     }
    41 }

    上述实例运行结果显示:
    p1和p2是否相等?true

    p1和p3是否相等?false

    p2和p3是否相等?false

    通常而言,正确地重写equals方法应该满足下列条件:

    • 自反性:对任意x,x.equals(x)一定返回true。
    • 对称性:对任意x和y,如果y.equals(x)返回true,则x.equals(y)也返回true。
    • 传递性:对任意x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)一定返回true。
    • 一致性:对任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应保持一致,要么一直是true,要么一直是false。
    • 对任何不是null的x,x.equals(null)一定返回false。

    特别注意:

    重新equals()方法后,一定要重写hashCode()方法,否则会引起一些意想不到的错误。

    所以,可以为上面的代码添加如下的hashCode()方法。

    1 public int hashCode() {
    2     final int PRIME = 31;
    3     int result = 1;
    4     result = PRIME * result + getId().hashCode();
    5     return result;
    6 }

    注意:不同类型hashCode值的计算可以采用如下公式。

    Field类型 计算公式
    boolean hashCode=(f?0:1);

    整数类型(byte,short,char,int)

    hashCode=(int)f;
    long   hashCode=(int)(f^(f>>>32));
    float hashCode=Float.floatToIntBits(f);
    double

    long l=Double.doubleToLongBits(f);

    hashCode=(int)(l^(l>>>32);

    普通引用类型 hashCode=f.hashCode();

    使用系数为31的原因如下:

    • 31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终的出来的结果只能被素数本身和被乘数还有1来整除!。(减少冲突)
    • 31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化.(提高算法效率)
    • 选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
    • 并且31只占用5bits,相乘造成数据溢出的概率较小。

    实例:

    Java中的集合有两类,一类是List,一类是Set。List内的元素是有序的,元素可以重复。Set元素无序,但元素不可重复。

    下面,通过一个实例来加深对equals和hashCode方法的理解。

      1 import java.util.HashSet;
      2 
      3 public class HashSetAndHashCodeTest {
      4     public static void main(String[] args) {
      5         HashSet<Point1> hs1 = new HashSet<Point1>();
      6         Point1 p11 = new Point1(3, 3);
      7         Point1 p12 = new Point1(3, 3);
      8         Point1 p13 = new Point1(3, 5);
      9         hs1.add(p11);
     10         hs1.add(p11);
     11         hs1.add(p12);
     12         hs1.add(p13);
     13         System.out.println(hs1.size()); //答案是3
     14 
     15 
     16         HashSet<Point2> hs2 = new HashSet<Point2>();
     17         Point2 p21 = new Point2(3, 3);
     18         Point2 p22 = new Point2(3, 3);
     19         Point2 p23 = new Point2(3, 5);
     20         hs2.add(p21);
     21         hs2.add(p22);
     22         hs2.add(p23);
     23         System.out.println(hs2.size()); // 答案是2。p21和p22被认为是同一个对象。
     24 
     25 
     26         HashSet<Point3> hs3 = new HashSet<Point3>();
     27         Point3 p31 = new Point3(3, 3);
     28         Point3 p32 = new Point3(3, 3);
     29         Point3 p33 = new Point3(3, 5);
     30         hs3.add(p31);
     31         hs3.add(p32);
     32         hs3.add(p33);
     33         System.out.println(hs3.size()); // 可能是2,可能是3。因为根据内存地址算出的hashcode不知道是否在一个区域。
     34     }
     35 }
     36 
     37 /**
     38  * 1 没有重写hashCode和equals的方法 
     39  */
     40 class Point1 {
     41     private int x;
     42     private int y;
     43 
     44     public Point1(int x, int y) {
     45         super();
     46         this.x = x;
     47         this.y = y;
     48     }
     49 
     50     public int getX() {
     51         return x;
     52     }
     53 
     54     public void setX(int x) {
     55         this.x = x;
     56     }
     57 
     58     public int getY() {
     59         return y;
     60     }
     61 
     62     public void setY(int y) {
     63         this.y = y;
     64     }
     65 }
     66 
     67 /**
     68  * 2 重写hashCode和equals的方法 *
     69  */
     70 class Point2 {
     71     private int x;
     72     private int y;
     73 
     74     Point2(int x, int y) {
     75         super();
     76         this.x = x;
     77         this.y = y;
     78     }
     79 
     80     @Override
     81     public int hashCode() {
     82         final int prime = 31;
     83         int result = 1;
     84         result = prime * result + x;
     85         result = prime * result + y;
     86         return result;
     87     }
     88 
     89     @Override
     90     public boolean equals(Object obj) {
     91         if (this == obj) return true;
     92         if (obj == null) return false;
     93         if (getClass() != obj.getClass()) return false;
     94         Point2 other = (Point2) obj;
     95         if (x != other.x) return false;
     96         if (y != other.y) return false;
     97         return true;
     98     }
     99 
    100     public int getX() {
    101         return x;
    102     }
    103 
    104     public void setX(int x) {
    105         this.x = x;
    106     }
    107 
    108     public int getY() {
    109         return y;
    110     }
    111 
    112     public void setY(int y) {
    113         this.y = y;
    114     }
    115 }
    116 
    117 
    118 /**
    119  * 3 没有重写hashCode的方法,但重写equals的方法
    120  */
    121 class Point3 {
    122     private int x;
    123     private int y;
    124 
    125     Point3(int x, int y) {
    126         super();
    127         this.x = x;
    128         this.y = y;
    129     }
    130 
    131     @Override
    132     public boolean equals(Object obj) {
    133         if (this == obj) return true;
    134         if (obj == null) return false;
    135         if (getClass() != obj.getClass()) return false;
    136         Point3 other = (Point3) obj;
    137         if (x != other.x) return false;
    138         if (y != other.y) return false;
    139         return true;
    140     }
    141 
    142     public int getX() {
    143         return x;
    144     }
    145 
    146     public void setX(int x) {
    147         this.x = x;
    148     }
    149 
    150     public int getY() {
    151         return y;
    152     }
    153 
    154     public void setY(int y) {
    155         this.y = y;
    156     }
    157 }

    对于自描述方法toString(),系统默认的方法如下:

    1 public String toString() {
    2     return getClass().getName() + "@" + Integer.toHexString(hashCode());
    3 }

    这样得到的并非自描述信息,而是实例的内存地址。所以,针对上面的Point1类,可以给出下面的自描述方法:

    1 public String toString() {
    2     return getClass().getName() + "@[x=" + this.getX() + ", y=" + this.getY() + "]";
    3 }


     

    参考内容:

     

  • 相关阅读:
    flume未解之谜
    flume source,sinks类型官方翻译
    flume-event类
    flume课件(连)
    source监控端口,telnet写入此端口。sinks指定目录,文件以默认时间滚动生成
    linux命令拾遗
    nginx内置变量
    nginx.conf
    hive事物开启
    hiveHA
  • 原文地址:https://www.cnblogs.com/bluepoint2009/p/Java-equals-method.html
Copyright © 2011-2022 走看看