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

 public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person("孙悟空", "1234");
Person p2 = new Person("孙行者", "1234");
Person p3 = new Person("孙大圣", "12345");
System.out.println("p1和p2是否相等?" + p1.equals(p2));
System.out.println("p1和p3是否相等?" + p1.equals(p3));
System.out.println("p2和p3是否相等?" + p2.equals(p3));
}
} class Person {
private String name;
private String id; public Person() {
}
public Person(String name, String id) {
this.name = name;
this.id = id;
} public String getId() {
return this.id;
}
public boolean equals(Object obj) {
//如果两个对象为同一个对象
if( this == obj) {
return true;
}
//当obj不为null,其它是Person类的实例时
if( obj != null && obj.getClass() == Person.class) {
Person obj2 = (Person)obj;
//并且当前对象的id与obj对象的id相等才可判断两个对象相等
if (this.getId().equals(obj2.getId())) {
return true;
}
}
return false;
}
}

上述实例运行结果显示:
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()方法。

 public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId().hashCode();
return result;
}

注意:不同类型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方法的理解。

 import java.util.HashSet;

 public class HashSetAndHashCodeTest {
public static void main(String[] args) {
HashSet<Point1> hs1 = new HashSet<Point1>();
Point1 p11 = new Point1(3, 3);
Point1 p12 = new Point1(3, 3);
Point1 p13 = new Point1(3, 5);
hs1.add(p11);
hs1.add(p11);
hs1.add(p12);
hs1.add(p13);
System.out.println(hs1.size()); //答案是3 HashSet<Point2> hs2 = new HashSet<Point2>();
Point2 p21 = new Point2(3, 3);
Point2 p22 = new Point2(3, 3);
Point2 p23 = new Point2(3, 5);
hs2.add(p21);
hs2.add(p22);
hs2.add(p23);
System.out.println(hs2.size()); // 答案是2。p21和p22被认为是同一个对象。 HashSet<Point3> hs3 = new HashSet<Point3>();
Point3 p31 = new Point3(3, 3);
Point3 p32 = new Point3(3, 3);
Point3 p33 = new Point3(3, 5);
hs3.add(p31);
hs3.add(p32);
hs3.add(p33);
System.out.println(hs3.size()); // 可能是2,可能是3。因为根据内存地址算出的hashcode不知道是否在一个区域。
}
} /**
* 1 没有重写hashCode和equals的方法
*/
class Point1 {
private int x;
private int y; public Point1(int x, int y) {
super();
this.x = x;
this.y = y;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
}
} /**
* 2 重写hashCode和equals的方法 *
*/
class Point2 {
private int x;
private int y; Point2(int x, int y) {
super();
this.x = x;
this.y = y;
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point2 other = (Point2) obj;
if (x != other.x) return false;
if (y != other.y) return false;
return true;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
}
} /**
* 3 没有重写hashCode的方法,但重写equals的方法
*/
class Point3 {
private int x;
private int y; Point3(int x, int y) {
super();
this.x = x;
this.y = y;
} @Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Point3 other = (Point3) obj;
if (x != other.x) return false;
if (y != other.y) return false;
return true;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
}
}

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

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

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

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

参考内容:

重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述方法的更多相关文章

  1. 如何编写出高质量的 equals 和 hashcode 方法?

    什么是 equals 和 hashcode 方法? 这要从 Object 类开始说起,我们知道 Object 类是 Java 的超类,每个类都直接或者间接的继承了 Object 类,在 Object ...

  2. 帮助新手理解equals和hashCode

    入行快要两年,偶尔想起来equals和hash还是会有些晕,索性今天就更深入的弄明白一些,不足之处也请各位大神指出批评,共同进步. 刚开始学java的时候只是记忆性的来背,如果一个类在程序中可能进行比 ...

  3. Java基础(六)判断两个对象相等:equals、hashcode、toString方法

    1.equal方法 Object类中的equal方法用于检测一个对象是否等于另外一个对象.在Object类中,这个方法将判断两个对象是否具有相同的引用.如果两个对象具有相同的引用,它们一定是相等的.然 ...

  4. 【Java基础之Object类(一)】Java中Object类中的所有方法(toString、equals、hashCode、clone、finalize、wait和notify等)详解(转载)

    java中的hashcode.equals和toString方法都是基类Object的方法. 首先说说toString方法,简单的总结了下API说明就是:返回该对象的字符串表示,信息应该是简明但易于读 ...

  5. 复写equals、hashCode和toString方法

    equals.hashCode和toString 这三个方法都是object类的方法,由于所有的类都是继承这个类,所以每一个类都有这三个方法. 1.复写equals方法 原则: 首先,两个实例是相同的 ...

  6. Java:验证在类继承过程中equals()、 hashcode()、toString()方法的使用

    以下通过实际例子对类创建过程汇中常用的equals().hashcode().toString()方法进行展示,三个方法的创建过程具有通用性,在项目中可直接改写. //通过超类Employee和其子类 ...

  7. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  8. java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问

    本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...

  9. Java基础:Object类中的equals与hashCode方法

    前言 这个系列的文章主要用来记录我在学习和复习Java基础知识的过程中遇到的一些有趣好玩的知识点,希望大家也喜欢. 一切皆对象   对于软件工程来说面向对象编程有一套完整的解决方案:OOA.OOD.O ...

随机推荐

  1. Soursight Insight 使用小结

    1.Soursight Insight中添加自需要的文件过滤器: options->document options ->add type document type name:scatt ...

  2. Css三栏布局自适应实现几种方法

    Css三栏布局自适应实现几种方法 自适应实现方法我们可以从三个方法来做,一个是绝对定位 ,自身浮动法 和margin负值法了,下面我们一起来看看这三个例子吧,希望例子能帮助到各位同学. 绝对定位法三栏 ...

  3. 按SCI影响因子排序的前50人工智能期刊列表

    附录二:按SCI影响因子排序的前50人工智能期刊列表 出版物名称,影响因子 IEEE TRANSACTIONS ON FUZZY SYSTEMS, 6.701    International Jou ...

  4. 【BZOJ】1025: [SCOI2009]游戏(置换群+dp+特殊的技巧+lcm)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1025 首先根据置换群可得 $$排数=lcm\{A_i, A_i表示循环节长度\}, \sum_{i= ...

  5. hdu 2019:数列有序!(数据结构,直接插入排序+折半插入排序)

    数列有序! Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submiss ...

  6. jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法

    本文实例讲述了jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法.分享给大家供大家参考.具体实现方法如下: 这里主要通过val方法设置按钮的文字,并用attr方法修改disabled属性实 ...

  7. Struts2_day04--自定义拦截器_Struts2的标签库_表单标签

    自定义拦截器 1 在struts2里面有很多的拦截器,这些拦截器是struts2封装的功能,但是在实际开发中,struts2里面的拦截器中可能没有要使用的功能,这个时候需要自己写拦截器实现功能 2 拦 ...

  8. Leetcode: Palindrome Partition I II

    题目一, 题目二 思路 1. 第一遍做时就参考别人的, 现在又忘记了 做的时候使用的是二维动态规划, 超时加超内存 2. 只当 string 左部分是回文的时候才有可能减少 cut 3. 一维动规. ...

  9. c++ rand()

    一.C++中不能使用random()函数 random函数不是ANSI C标准,不能在gcc,vc等编译器下编译通过.但在C语言中int random(num)可以这样使用,它返回的是0至num-1的 ...

  10. post 与get

    GET:从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改. POST:向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据. 补充: PUT:PUT的英文含义是放置,也 ...