Java 重写hashCode()与equals()
为什么要重写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()的更多相关文章
- Java 重写 hashCode() 和 equals() 方法
1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...
- 【java编程】重写HashCode和equals方法
[一]重写equals方案的规则 equals方法本来的原则 1.类的每个实例本质上都是唯一的. 2.不关心类是否提供了“逻辑相等”的测试功能 3.超类已经覆盖了equals,从超类继承过来的行为对于 ...
- java中hashcode和equals的区别和联系
HashSet和HashMap一直都是JDK中最常用的两个类,HashSet要求不能存储相同的对象,HashMap要求不能存储相同的键. 那么Java运行时环境是如何判断HashSet中相同对象.Ha ...
- 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。
我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...
- (转)为什么要重写 hashcode 和 equals 方法?
作者丨hsm_computer cnblogs.com/JavaArchitect/p/10474448.html 我在面试Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候 ...
- 深入探究Java中hashCode()和equals()的关系
目录 一.基础:hashCode() 和 equals() 简介 equals() hashCode() 二. 漫谈:初识 hashCode() 与 equals() 之间的关系 三. 解密:深入理解 ...
- HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法
之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...
- 面试题:我们重写一个对象的时候为什么要同时重写hashcode()和equals()方法
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 在创建的类不重写hashCode()和equals() 方法时,默认使用 java 提供的 java.l ...
- Java中HashCode()和equals()的作用
引言 我们知道Java中的集合(Collection)大致可以分为两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复:后者元素无序,但元素不可重复. 这里就引出一个问题: ...
随机推荐
- 浅谈进程&线程
学习过操作系统(下面简称OS)的都清楚,计算机计算的核心是CPU,操作系统是计算机资源的管理者 同事也是软硬件之间的接口.为了实现程序的并发,而引入了进程的概念.在传统OS中,进程是个很重要的概念,它 ...
- [SD心灵鸡汤]007.每月一则 - 2015.11
1.不要因为世界太过复杂,而背叛了你的单纯. 2.人的一生要疯狂一次,无论是为一个人,一段情,一段路途或一个梦想. 3.时间真的很神奇,你永远不知道它会如何改变你.换句话说:以前难吃的蔬菜.苦涩的啤酒 ...
- [JavaWeb基础] 021.Action中result的各种转发类型
在struts2中, struts.xml中result的类型有多种,它们类似于struts1中的forward,常用的类型有dispatcher(默认值).redirect.redirectActi ...
- Redis详解(十二)------ 缓存穿透、缓存击穿、缓存雪崩
本篇博客我们来介绍Redis使用过程中需要注意的三种问题:缓存穿透.缓存击穿.缓存雪崩. 1.缓存穿透 一.概念 缓存穿透:缓存和数据库中都没有的数据,可用户还是源源不断的发起请求,导致每次请求都会到 ...
- VUE 子组件向父组件传值 , 并且触发父组件方法(函数)
目标:封装一个 搜索组件 <子组件需要传一个或者多个搜索参数到父组件,然后父组件执行列表查询函数> 1.子组件 <div> <input v-model="l ...
- java方法句柄-----3.方法句柄的实现接口
目录 1.使用方法句柄实现接口 1.使用方法句柄实现接口 2.3节介绍的动态代理机制可以在运行时为多个接口动态创建实现类,并拦截通过接口进行的方法调用.方法句柄也具备动态实现一个接口的能力.这是通 ...
- 初步理解 MySQL数据库
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1. 索引是做什么的? 索引用于快速找出在某个列中有一特定值的行.不使用索引,MYSQL必须从第1条记录 ...
- Java实现蓝桥杯 最短路
问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环).请你计算从1号点到其他点的最短路(顶点从1到n编号). 输入格式 第一行两个整数n, m. 接下来的m行,每行有三个 ...
- Java实现 蓝桥杯VIP 算法提高 选择排序
算法提高 选择排序 时间限制:1.0s 内存限制:256.0MB 选择排序 问题描述 排序,顾名思义,是将若干个元素按其大小关系排出一个顺序.形式化描述如下:有n个元素a[1],a[2],-,a[ ...
- java实现土地测量
** 土地测量** 造成高房价的原因有许多,比如土地出让价格.既然地价高,土地的面积必须仔细计算.遗憾的是,有些地块的形状不规则,比如是如图[1.jpg]中所示的五边形. 一般需要把它划分为多个三角形 ...