重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述方法
下面给出一个实例,重新编写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() + "]";
}
参考内容:
- http://www.oschina.net/question/82993_75533
- http://www.2cto.com/kf/201211/168714.html
- http://howtodoinjava.com/2012/10/09/working-with-hashcode-and-equals-methods-in-java/
重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述方法的更多相关文章
- 如何编写出高质量的 equals 和 hashcode 方法?
什么是 equals 和 hashcode 方法? 这要从 Object 类开始说起,我们知道 Object 类是 Java 的超类,每个类都直接或者间接的继承了 Object 类,在 Object ...
- 帮助新手理解equals和hashCode
入行快要两年,偶尔想起来equals和hash还是会有些晕,索性今天就更深入的弄明白一些,不足之处也请各位大神指出批评,共同进步. 刚开始学java的时候只是记忆性的来背,如果一个类在程序中可能进行比 ...
- Java基础(六)判断两个对象相等:equals、hashcode、toString方法
1.equal方法 Object类中的equal方法用于检测一个对象是否等于另外一个对象.在Object类中,这个方法将判断两个对象是否具有相同的引用.如果两个对象具有相同的引用,它们一定是相等的.然 ...
- 【Java基础之Object类(一)】Java中Object类中的所有方法(toString、equals、hashCode、clone、finalize、wait和notify等)详解(转载)
java中的hashcode.equals和toString方法都是基类Object的方法. 首先说说toString方法,简单的总结了下API说明就是:返回该对象的字符串表示,信息应该是简明但易于读 ...
- 复写equals、hashCode和toString方法
equals.hashCode和toString 这三个方法都是object类的方法,由于所有的类都是继承这个类,所以每一个类都有这三个方法. 1.复写equals方法 原则: 首先,两个实例是相同的 ...
- Java:验证在类继承过程中equals()、 hashcode()、toString()方法的使用
以下通过实际例子对类创建过程汇中常用的equals().hashcode().toString()方法进行展示,三个方法的创建过程具有通用性,在项目中可直接改写. //通过超类Employee和其子类 ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问
本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...
- Java基础:Object类中的equals与hashCode方法
前言 这个系列的文章主要用来记录我在学习和复习Java基础知识的过程中遇到的一些有趣好玩的知识点,希望大家也喜欢. 一切皆对象 对于软件工程来说面向对象编程有一套完整的解决方案:OOA.OOD.O ...
随机推荐
- Soursight Insight 使用小结
1.Soursight Insight中添加自需要的文件过滤器: options->document options ->add type document type name:scatt ...
- Css三栏布局自适应实现几种方法
Css三栏布局自适应实现几种方法 自适应实现方法我们可以从三个方法来做,一个是绝对定位 ,自身浮动法 和margin负值法了,下面我们一起来看看这三个例子吧,希望例子能帮助到各位同学. 绝对定位法三栏 ...
- 按SCI影响因子排序的前50人工智能期刊列表
附录二:按SCI影响因子排序的前50人工智能期刊列表 出版物名称,影响因子 IEEE TRANSACTIONS ON FUZZY SYSTEMS, 6.701 International Jou ...
- 【BZOJ】1025: [SCOI2009]游戏(置换群+dp+特殊的技巧+lcm)
http://www.lydsy.com/JudgeOnline/problem.php?id=1025 首先根据置换群可得 $$排数=lcm\{A_i, A_i表示循环节长度\}, \sum_{i= ...
- hdu 2019:数列有序!(数据结构,直接插入排序+折半插入排序)
数列有序! Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Submiss ...
- jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法
本文实例讲述了jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法.分享给大家供大家参考.具体实现方法如下: 这里主要通过val方法设置按钮的文字,并用attr方法修改disabled属性实 ...
- Struts2_day04--自定义拦截器_Struts2的标签库_表单标签
自定义拦截器 1 在struts2里面有很多的拦截器,这些拦截器是struts2封装的功能,但是在实际开发中,struts2里面的拦截器中可能没有要使用的功能,这个时候需要自己写拦截器实现功能 2 拦 ...
- Leetcode: Palindrome Partition I II
题目一, 题目二 思路 1. 第一遍做时就参考别人的, 现在又忘记了 做的时候使用的是二维动态规划, 超时加超内存 2. 只当 string 左部分是回文的时候才有可能减少 cut 3. 一维动规. ...
- c++ rand()
一.C++中不能使用random()函数 random函数不是ANSI C标准,不能在gcc,vc等编译器下编译通过.但在C语言中int random(num)可以这样使用,它返回的是0至num-1的 ...
- post 与get
GET:从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改. POST:向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据. 补充: PUT:PUT的英文含义是放置,也 ...