下面给出一个实例,重新编写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. C++ 构造函数的对象初始化列表

    //构造函数的对象初始化列表 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class P ...

  2. addLoadEvent

    function addLoadEvent(func){ var oldOnload = window.onload; if(typeof(window.onload) != 'function'){ ...

  3. Linux系统下修改MySQL密码(忘记密码)

    忘记原来的myql的root的密码: 首先,你必须要有操作系统的root权限了.要是连系统的root权限都没有的话,先考虑root系统再走下面的步骤.类似于安全模式登录系统,有人建议说是pkill m ...

  4. 谈谈Jquery ajax中success和complete有哪些不同点

    记录下,以备将来有需时用 http://www.jb51.net/article/75206.htm

  5. error C2678: 二进制“+”: 没有找到接受“const char [22]”类型的左操作数的运算符(或没有可接受的转换)没有与这些操作数匹配的“+”运算符

    错误:没有与这些操作数匹配的“+”运算符,操作数类型为const char [20]+CString 分析原因:其提示操作数类型为const char [20]+CString 可见是类型有问题 故加 ...

  6. Mongodb默认开启与关闭

    默认启动:   $ ./mongodb   默认数据保存路径:/data/db/ 默认端口:27017   修改默认路径:   --dbpath $ ./mongdb --dbpath /mongod ...

  7. ios应用, 设置不自己主动备份到iCloud

    原创文章,转载请注明出处 ios项目,假设有内置下载或者程序动态生成文件的话,就要注意所下载或生成的文件,要不要自己主动备份到iCloud 假设没有合适的理由就自己主动上传大文件的话,可能在不能通过应 ...

  8. 剑指 offer set 11 最小的K个数

    总结 1. 假如允许修改给定数组, 那么通过快排的子过程, 可以在 o(n) 时间复杂度内得出结果. 2. 对于海量数据和不允许修改的数据, 通过最小堆的方式更好, 通过维持一个大小为 K 的最小堆

  9. 第十五篇:C程序的存储空间布局

    前言 C语言程序的执行必定需要耗费一定的资源,也就是说,程序在计算机内部的映像不可能就单单代码. 本文将讲解C语言程序在计算机内部的存在方式. 程序存储空间 1. 正文段:程序的机器指令部分 2. 初 ...

  10. JZOJ.5315【NOIP2017模拟8.19】小串串

    Description