为什么要重写hashCode() 和 equals()

equals()

默认的Object类里面equals()方法是根据对象所在的内存来做判断的,如果两个对象引用指向的是同一个内存,则返回true,但是,在某些场景一下,我们不想这么苛刻,比如是String类的equals(),只是判断了String.value的值,String其它的属性是不参与判断的,所以我们比较字符串的时候只是比较其中的内容,下面是String的equals()方法和hashCode()方法。

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
} public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value; for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}

hashCode()

一般而言,默认的hashCode()方法会返回一个与对象的内存地址相关的值,有时候直接就是内存地址;所以,如何两个对象的hashCode()不相等,则它们肯定是不相等;但反过来,如果两个对象的hashCode()相等,它们不一定是相等的。

如果我们创建了属于自己的Class,还使用默认的hashCode()方法,那就可以出错,特别是在使用该Class作为HashMap的Key的时候。

重写hashCode()的基本原则

该基本原则是参考《Effective Java》Joshua Bloch's recipe

A、初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
B、选取equals方法中用于比较的所有域(之所以只选择equals()中使用的域,是为了保证上述原则的第1条),然后针对每个域的属性进行计算:
(1) boolean,c = f ? 1:0
(2) byte\char\short\int,  c= (int)f
(3) long,c = (int)(f ^ (f >>> 32))
(4) float,c = Float.floatToIntBits(f)
(5) double,long l = Double.doubleToLongBits(f),c = (int)(l ^ (l >>> 32))
(6) Object,对里面的属性采用上面同一的方法来判断
(7) 如果是数组,那么需要为每个元素当做单独的域来处理。java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。
(8)、最后,把每个域的散列码合并到对象的哈希码中。

一个具体例子

public class Person {

    private String name;

    private byte[] password ;

    private String nickname ; // ignore the nickname

    private int age ;

    private double height ;

    private long birthYear ;

    private float sex ;

    private boolean alive;

    public Person(String name, byte[] password, int age, double height, long birthYear, float sex, boolean alive , String nickname) {
this.name = name;
this.password = password;
this.nickname = nickname;
this.age = age;
this.height = height;
this.birthYear = birthYear;
this.sex = sex;
this.alive = alive;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public byte[] getPassword() {
return password;
} public void setPassword(byte[] password) {
this.password = password;
} public String getNickname() {
return nickname;
} public void setNickname(String nickname) {
this.nickname = nickname;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public double getHeight() {
return height;
} public void setHeight(double height) {
this.height = height;
} public long getBirthYear() {
return birthYear;
} public void setBirthYear(long birthYear) {
this.birthYear = birthYear;
} public float getSex() {
return sex;
} public void setSex(float sex) {
this.sex = sex;
} public boolean isAlive() {
return alive;
} public void setAlive(boolean alive) {
this.alive = alive;
} /**
* Joshua Bloch's recipe
* @return int
*/
@Override
public int hashCode() {
int result = 17 ;
result = 37 * result + name.hashCode();
result = 37 * result + Arrays.hashCode(password);
result = 37 * result + age;
long l = Double.doubleToLongBits(height);
result = 37 * result + (int)(l ^ (l >>> 32));
result = 37 * result + (int)(birthYear ^ (birthYear >>> 32));
result = 37 * result + Float.floatToIntBits(sex);
result = 37 * result + (alive ? 0 : 1 );
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj){
return true;
}
if (obj instanceof Person){
Person anotherPerson = (Person)obj;
if (this.getName().equals(anotherPerson.getName())
&& Arrays.equals(this.getPassword(),anotherPerson.getPassword())
&& this.age == anotherPerson.getAge()
&& this.height == anotherPerson.getHeight()
&& this.birthYear == anotherPerson.getBirthYear()
&& this.sex == anotherPerson.getSex()
&& this.alive == anotherPerson.isAlive()
){
return true;
}else {
return false;
}
}
return false;
}
} public class Main { public static void main(String[] args) {
String name = "Tom";
byte [] password = "123".getBytes();
int age = 18 ;
double height = 3.14;
long birthYear = 2000 ;
float sex = 1 ;
boolean alive = true ;
Person Tom = new Person(name,password,age,height,birthYear,sex,alive,"Tom");
Person Deal = new Person(name,password,13,height,birthYear,sex,alive,"Deal");
Person Jack = new Person(name,password,age,height,birthYear,sex,alive,"Jack"); // map是根据hashcode来判断的,然后还有疑惑,尝试把 Person.hashcode函数注释再运行程序,你会明白
Map<Person,String> personStringMap = new HashMap<Person, String>(10);
personStringMap.put(Tom,"Tom");
personStringMap.put(Deal,"Deal"); System.out.println("Tom's nickname is : "+personStringMap.get(Tom));
System.out.println("Jack's nickname is : "+personStringMap.get(Jack));
System.out.println("Deal's nickname is : "+personStringMap.get(Deal));
System.out.println("is Tom equals to Jack : "+Tom.equals(Jack)); // list 的contains 是根据equal方法来判断的
List<Person> persons = new ArrayList<Person>();
persons.add(Tom);
persons.add(Deal);
System.out.println("persons contains Jack: " + persons.contains(Jack));
System.out.println("persons contains Deal: " + persons.contains(Deal));
}
}

参考 http://www.cnblogs.com/kismetv/p/7191736.html

参考 https://www.cnblogs.com/dolphin0520/p/3681042.html

Java 重写hashCode()与equals()的更多相关文章

  1. Java 重写 hashCode() 和 equals() 方法

    1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...

  2. 【java编程】重写HashCode和equals方法

    [一]重写equals方案的规则 equals方法本来的原则 1.类的每个实例本质上都是唯一的. 2.不关心类是否提供了“逻辑相等”的测试功能 3.超类已经覆盖了equals,从超类继承过来的行为对于 ...

  3. java中hashcode和equals的区别和联系

    HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...

  4. 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

    我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...

  5. (转)为什么要重写 hashcode 和 equals 方法?

    作者丨hsm_computer cnblogs.com/JavaArchitect/p/10474448.html 我在面试Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候 ...

  6. 深入探究Java中hashCode()和equals()的关系

    目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...

  7. HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法

    之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...

  8. 面试题:我们重写一个对象的时候为什么要同时重写hashcode()和equals()方法

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 在创建的类不重写hashCode()和equals() 方法时,默认使用 java 提供的 java.l ...

  9. Java中HashCode()和equals()的作用

    引言 我们知道Java中的集合(Collection)大致可以分为两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复:后者元素无序,但元素不可重复. 这里就引出一个问题: ...

随机推荐

  1. Python 每日一练(6)

    引言 今天的练习可以说是昨天的那个的反操作,今天要尝试将xls文件的内容写入xml文件中 所涉及到的库有xml,xlrd xls文件内容写入xml python操作excel主要用到xlrd和xlwt ...

  2. 突发!HashiCorp禁止在中国使用企业版VAULT软件

    目录 前言 HashiCorp公司介绍 HashiCorp旗下的软件 Provision Secure Connect Run 总结 前言 昨天HashiCorp突然发布一则消息,禁止在中国使用Vau ...

  3. SpringBoot系列—简单的邮件系统

    1. 效果发送效果图 2. 邮件开发准备工作 3. springboot引入mail服务 4. 启动应用,开始4种邮件发送测试 1. 效果发送效果图 连续发送了四封邮件:普通文本邮件,带附件的邮件,内 ...

  4. STM32串口DMA接收数据错位——暴力解决方法

    背景:两片STM32通过串口通信,为了减小CPU负担,采用DMA进行通信,发送端为STM32F103C8T6,接收端为STM32F407VET6.在调试的过程中发现,一直出现数据错位的问题,接收端尝试 ...

  5. JS实现PC端URL跳转到对应移动端URL

    在做移动端网站时,有时因技术问题或其他原因无法制作响应式版面,而移动端页面只能放到子目录下,但是手机端通过搜索引擎进入网站电脑端子页面,无法匹配到移动端页面,使得用户体验很不好,即影响排名也影响转化. ...

  6. 非阻塞赋值(Non-blocking Assignment)是个伪需求

    https://mp.weixin.qq.com/s/mH84421WDGRb7cuU5FEFIQ Verilog的赋值很是复杂,包括: 1. Continuous assignment; 2. Pr ...

  7. pycharm关联git

    一.先创建SSH Key 给github设置SSH-KEY !!! 这一步算是连接GitHub的最基本的一步了,git是分布式的代码管理工具,远程的代码管理是基于ssh的,所以得先配好SSH key. ...

  8. Linux (三) 基础命令 上

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一 . 背景知识 1. Linux系统中一切皆文件 在Linux系统中任何东西都是以文件形式来存储的.这 ...

  9. 8.0 以上版本 mySQL数据库导致的命令行可连接,NaviCat不可连接的问题

    错误代码: client does not support authentication 原因: 没有开启Mysql的远程连接配置 解决办法: 1 使用命令行进入数据库 C:\Users\wushao ...

  10. Java实现 LeetCode 面试题62. 圆圈中最后剩下的数字(约瑟夫环)

    面试题62. 圆圈中最后剩下的数字 0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 例如,0.1.2.3.4这5个数字组成一个圆 ...