重新编写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 ...
随机推荐
- 使用javascript操作cookies的实例
<script> //写cookies函数 作者:翟振凯 function SetCookie(name,value)//两个参数,一个是cookie的名子,一个是值 { var Days ...
- 【UVa】And Then There Was One(dp)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- Linux心得记录
2014.4.8 linux环境下如何删除一个目录? rm -r linux本身提供删除目录命令——rmdir,但是如果你要删除的目录中含有子目录或者子文件,那么该命令会提示“删除失败:目录非空“也就 ...
- ReactNative iOS源码解析
http://awhisper.github.io/2016/06/24/ReactNative%E6%B5%81%E7%A8%8B%E6%BA%90%E7%A0%81%E5%88%86%E6%9E% ...
- 【BZOJ4244】邮戳拉力赛 DP
[BZOJ4244]邮戳拉力赛 Description IOI铁路是由N+2个站点构成的直线线路.这条线路的车站从某一端的车站开始顺次标号为0...N+1. 这条路线上行驶的电车分为上行电车和下行电车 ...
- 一些VS2013的使用技巧(转载)
1. Peek View 可以在不新建TAB的情况下快速查看.编辑一个函数的代码. 用法:在光标移至某个函数下,按下alt+F12. 然后在Peek窗口里可以继续按alt+F12.然后按ctrl+al ...
- 160607、springmvc+spring使用taskExecutor
第一步:导入spring core的jar+springmvc的jar 第二步:springmvc的配置文件中 <bean id="taskExecutor" class=& ...
- WingIDE6.0神秘代码
python2: import string import random import sha BASE16 = '0123456789ABCDEF' BASE30 = '123456789ABCDE ...
- HDU 1866 A + B forever!
A + B forever! Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- Code Forces 21C Stripe 2
C. Stripe 2 time limit per test 1 second memory limit per test 64 megabytes input standard input out ...