一:怎样重写equals()方法?
重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。要想正确改写equals()方法,你必须要遵守它的通用约定。下面是约定的内容,来自java.lang.Object的规范:
equals方法实现了等价关系(equivalence relation):
1. 自反性:对于任意的引用值x,x.equals(x)一定为true。
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,
y.equals(x)也一定返回true。
3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,
并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。
4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修
改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。
5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。
二:重写equals方法的要点:
1. 使用==操作符检查“实参是否为指向对象的一个引用”。
2. 使用instanceof操作符检查“实参是否为正确的类型”。
3. 把实参转换到正确的类型。
4. 对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹
配。对于既不是float也不是double类型的基本类型的域,可以使用==操作符
进行比较;对于对象引用类型的域,可以递归地调用所引用的对象的equals方法;
对于float类型的域,先使用Float.floatToIntBits转换成int类型的值,
然后使用==操作符比较int类型的值;对于double类型的域,先使用
Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较
long类型的值。
5. 当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传
递的、一致的?(其他两个特性通常会自行满足)如果答案是否定的,那么请找到
这些特性未能满足的原因,再修改equals方法的代码。
三:hashCode
hashCode主要是用于散列集合,通过对象hashCode返回值来与散列中的对象进行匹配,通过hashCode来查找散列中对象的效率为O(1),如果多个对象具有相同的hashCode,那么散列数据结构在同一个hashCode位置处的元素为一个链表,需要通过遍历链表中的对象,并调用equals来查找元素。这也是为什么要求如果对象通过equals比较返回true,那么其hashCode也必定一致的原因。
为对象提供一个高效的hashCode算法是一个很困难的事情。理想的hashCode算法除了达到本文最开始提到的要求之外,还应该是为不同的对象产生不相同的hashCode值,这样在操作散列的时候就完全可以达到O(1)的查找效率,而不必去遍历链表。假设散列中的所有元素的hashCode值都相同,那么在散列中查找一个元素的效率就变成了O(N),这同链表没有了任何的区别。
hashCode()的返回值和equals()的关系如下:
- 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
- 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。
四.设计hashCode()
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=31*result+c;
[4]返回result。
这个算法存在这么几个问题需要探讨:
1. 为什么初始值要使用非0的整数?这个的目的主要是为了减少hash冲突,考虑这么个场景,如果初始值为0,并且计算hash值的前几个域hash值计算都为0,那么这几个域就会被忽略掉,但是初始值不为0,这些域就不会被忽略掉,示例代码:
01 |
import java.io.Serializable;
|
03 |
public class Test implements Serializable {
|
05 |
private static final long serialVersionUID = 1L;
|
07 |
private final int [] array;
|
09 |
public Test( int ... a) {
|
14 |
public int hashCode() {
|
16 |
for ( int element : array) {
|
17 |
result = 31 * result + element;
|
22 |
public static void main(String[] args) {
|
23 |
Test t = new Test( 0 , 0 , 0 , 0 );
|
24 |
Test t2 = new Test( 0 , 0 , 0 );
|
25 |
System.out.println(t.hashCode());
|
26 |
System.out.println(t2.hashCode());
|
如果hashCode中result的初始值为0,那么对象t和对象t2的hashCode值都会为0,尽管这两个对象不同。但如果result的值为17,那么计算hashCode的时候就不会忽略这些为0的值,最后的结果t1是15699857,t2是506447
2. 为什么每次需要使用乘法去操作result? 主要是为了使散列值依赖于域的顺序,还是上面的那个例子,Test t = new Test(1, 0)跟Test t2 = new Test(0, 1), t和t2的最终hashCode返回值是不一样的。
3. 为什么是31? 31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。
相关推荐
这个源码资源是关于Java中的Object类的讲解案例代码。Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景...
首先我们先来看下String类的源码:可以发现String是重写了Object类的equals方法的,并且也重写了hashcode方法
个人学习终结成果:为什么要重新equals和hashCode方法?如何重写?站好马步需从j2se基础开始
hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。 使用hashCode()和equals() hashCode()方法被用来获取给定对象的整数。这个整数被用来确定对象被...
equals():反映的是对象或变量具体...根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
面试官瞬间就饱了,重写equals函数,需要重写hashCode函数吗? 面试官问我,为什么重写equals函数,必须重写hashCode函数,我当时就懵住了。 然后扯天扯地,然后面试官瞬间就饱了,痛定思痛,写下这篇博客 首先看...
Object 类是所有类的父类,其 equals 方法比较的是两个对象的引用指向的地址,hashcode 是一个本地方法,返回的是对象地址值。他们都是通过比较地址来比较对象是否相等的
提供了20道高难度的Java Object类面试题及详细答案解析,涵盖了equals()、hashCode()、toString()、clone()、finalize()等方法的重写和应用,以及对象的比较、克隆、标识哈希码等概念。适合准备Java面试的开发者深入...
20、Object类的equal和hashCode方法重写,为什么? 21-40题 21、List,Set,Map的区别 26、ArrayMap和HashMap的对比 29、HashMap和HashTable的区别 30、HashMap与HashSet的区别 31-40题 31、HashSet与HashMap...
为什么重写 equals() 时必须重写 hashCode() 方法? String String、StringBuffer、StringBuilder 的区别? String 为什么是不可变的? 字符串拼接用“+” 还是 StringBuilder? String#equals() 和 Object#equals() ...
如果不是想使用object类,toString方法,可以重写此方法 equals方法 equals方法比较对象的是否相同 ==比较两个对象的内存地址 如果想表示对象的内容相同,返回true,则重写此方法 hashCode 返回一个hash code码,...
==与equals的比较,包装类的使用
string 类重写equals:比较的是每一个字符是否相等 hashCode(重写equals就一定要重写hashCode) 没有重写hashCode值不会变,重写了hashCode值就会改变 总结:==跟equals的区别 1. ==既可以比较基本
用来鉴定两个对象是否相等,Object类中的hashCode方法返回对象在内存中地址转换成的一个int值,所以如果没有重写hashCode方法,任何对象的hashCode方法是不相等的。 int、char、long各占多少字节数 4、1或2或4、8 ...
java中==和equals和hashCode的区别 1)基本数据类型,也称原始数据类型byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。 2) 引用类型(类、接口、数组) 当他们用...
equals和hashcode方法 143 泛型 144 思考作业 145 上机作业 145 第八章 IO技术 146 为什么需要学习IO技术 146 基本概念 146 数据源 146 流的概念 146 第一个简单的IO流程序及深入(将文件中的数据读入) 146 Java...
学生提问:既然内部类是外部类的成员,是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类? 211 6.7.4 局部内部类 211 6.7.5 匿名内部类 212 6.7.6 闭包(Closure)和回调 215 6.8 ...
equals()方法和hashCode()方法 270 数据结构 273 Array方法类汇总 304 Java数组与集合小结 305 递归 309 对象的序列化 310 Java两种线程类:Thread和Runnable 315 Java锁小结 321 java.util.concurrent.locks包下...
第9章 常用类 4课时 理解Object类及其常用方法equals,hashCode和finalize等。 能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 ...
java snmp 源码 [TOC] Spring相关 spring 优点,特性 spring IOC AOP,aop如何实现 ...JDK动态代理和cgLib动态代理 ...BeanFactory和FactoryBean区别 ...Java相关 ...同时重写equals和hashcode wait,noti