谈谈hashcode和equals的用法
HASH:
Hash是散列的意思,就是把任意长度的输入,通过散列算法变换成固定长度的输出,该输出就是散列值。关于散列值,有以下几个关键结论:
1、如果散列表中存在和散列原始输入K相等的记录,那么K必定在f(K)的存储位置上
2、不同关键字经过散列算法变换后可能得到同一个散列地址,这种现象称为碰撞
3、如果两个Hash值不同(前提是同一Hash算法),那么这两个Hash值对应的原始输入必定不同
几种常见的hash算法:
(1) MD4
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。
(2) MD5
MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好
(3) SHA-1 及其他
SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。
equals的使用:
在Java语言中,equals方法在使用时:
针对包装对象,比较的是对象的值(包括 boolean,byte,char,short,int,long,float,double)
针对String对象,比较的也是String的值(因为String内部重写了equals方法和hashCode方法)
针对其他object对象,比较的是两个对象的引用是否指向同一个内存地址
hashcode:
1、HashCode的存在主要是为了查找的快捷性,在对象存储的散列表里面,hashCode用来指定对象存储的内存地址。而equals用来判断对象的引用是否指向同一个地址,也就是判断两个对象的hashCode值是否一致
2、如果两个对象equals相等,那么这两个对象的HashCode一定也相同
3、如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写
4、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置
再归纳一下就是hashCode是用于查找使用的,而equals是用于比较两个对象的是否相等的。
hashcode作用:
1.hashcode是用来查找的,提高我们的查询效率。
如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0 1 2 3 4 5 6 7
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。 2.hashcode规定,如果两个类的HashCode都不相同,那么这两个类必定是不同的。用在hashset结构中,就可以大大减少实际调用equals方法的次数,提高效率。
但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊
为什么重写Object的equals(Object obj)方法尽量要重写Object的hashCode()方法?
具体事例:
public class HashTest {
private int i;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public int hashCode() {
return i % 10;
}
public final static void main(String[] args) {
HashTest a = new HashTest();
HashTest b = new HashTest();
a.setI(1);
b.setI(1);
Set<HashTest> set = new HashSet<HashTest>();
set.add(a);
set.add(b);
System.out.println(a.hashCode() == b.hashCode());
System.out.println(a.equals(b));
System.out.println(set);
}
}
输出结果:
true
false
[com.ubs.sae.test.HashTest@1, com.ubs.sae.test.HashTest@1]
以上这个示例,我们只是重写了hashCode方法,从上面的结果可以看出,虽然两个对象的hashCode相等,但是实际上两个对象并不是相等;,我们没有重写equals方法,那么就会调用object默认的equals方法,是比较两个对象的引用是不是相同,显示这是两个不同的对象,两个对象的引用肯定是不定的。这里我们将生成的对象放到了HashSet中,而HashSet中只能够存放唯一的对象,也就是相同的(适用于equals方法)的对象只会存放一个,但是这里实际上是两个对象a,b都被放到了HashSet中,这样HashSet就失去了他本身的意义了。
此时我们把equals方法给加上:
public class HashTest {
private int i;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
<span style="color:#3366FF;"><strong>public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (!(object instanceof HashTest)) {
return false;
}
HashTest other = (HashTest) object;
if (other.getI() == this.getI()) {
return true;
}
return false;
}</strong></span>
public int hashCode() {
return i % 10;
}
public final static void main(String[] args) {
HashTest a = new HashTest();
HashTest b = new HashTest();
a.setI(1);
b.setI(1);
Set<HashTest> set = new HashSet<HashTest>();
set.add(a);
set.add(b);
System.out.println(a.hashCode() == b.hashCode());
System.out.println(a.equals(b));
System.out.println(set);
}
}
此时得到的结果就会如下:
true
true
[com.ubs.sae.test.HashTest@1]
从结果我们可以看出,现在两个对象就完全相等了,HashSet中也只存放了一份对象。
关于String的hashCode方法
要注意的是,String重写了hashCode方法。这是因为散列表(hash表)操作中费时多的部分就是计算hashCode方法,所以在String类中的hashCode方法包含一个重要的优化:每个String对象内部都存储了它的hashCode值,该值初始为0,但如果hashCode方法被调用,那么这个值就将会被记住,下一次使用的时候可以直接调用出来,而不用再计算一次。之所以能这样实现,是由于String类是不可改变的。所以hashCode值被计算之后也并不会发生变化。
String类的hashCode的实现,简要摘录如下:
public final class String{
private int hash = 0;
public int hashCode(){
if(hash != 0){
return hash;
}
for(int i=0; i<length(); i++){
hash = hash * 31 + (int) charAt(i);
}
return hash;
}
}
谈谈hashcode和equals的用法的更多相关文章
- hashCode()和equals()的用法
使用hashCode()和equals() hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法. hashCode()方法 ...
- Java 中正确使用 hashCode 和 equals 方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- (转)Java 中正确使用 hashCode 和 equals 方法
背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...
- Java中正确使用hashCode和equals方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- java中hashcode()和equals()的详解
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...
- 使用hashCode()和equals()方法 - Java
在这篇文章中,我将指出我对hashCode()和equals()方法的理解.我将讨论它们的默认实现以及如何正确地覆盖它们.我还将使用Apache Commons包中的实用工具类来实现这些方法. has ...
- JAVA基础4——谈谈HashCode与HashMap相关概念
谈谈HashCode与HashMap HashCode hashCode,即一个Object的散列码. HashCode的作用: 对于List.数组等集合而言,HashCode用途不大: 对于Hash ...
- hashcode、equals和 ==详解
两个对象值相同(x.equals(y) == true),则一定有相同的hash code: 这是java语言的定义: 因为:Hash,一般翻译做“散列”,也有直接音译为"哈希"的 ...
- 对hashcode、equals的理解
1.首先hashcode和equals都是java每个对象都存在的方法,因为他们两是Object的方法. 2.hashcode方法默认返回的是该对象内存地址的哈希码,然而你会发现,Object类中没有 ...
随机推荐
- master.sys.sysprocesses相关内容
sysprocesses 表中保存关于运行在 Microsoft® SQL Server™ 上的进程的信息.这些进程可以是客户端进程或系统进程. sysprocesses 只存储在 master 数据 ...
- <td>标签clospan和rowspan 可横跨列数和行数
<td colspan="2"> <input type="text" name="reason_other" size= ...
- Rabbit的事务
加入事务的方法: txSelect() txCommit() txRollback() 生产者: package com.kf.queueDemo.transactions; import jav ...
- hdu 4628 Pieces 状态压缩dp
Pieces Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total S ...
- git基本命令集合
以下内容不适合初学者 括号中表示需要自己填写 v1.0 git add git commit -m git commit -a -m git commit -amend git clone git l ...
- java.sql.SQLException: Incorrect string value: '\xF0\x9F\x9A\x80\xF0\x9F...' for column 'name' at row 1
1.异常提示: 12:59:10.000 [http-nio-8080-exec-40] DEBUG o.s.j.s.SQLStateSQLExceptionTranslator - Extracte ...
- listview cacheColorHint,listSelector属性
ListView是常用的显示控件,默认背景是和系统窗口一样的透明色,如果给ListView加上背景图片,或者背景颜色时,滚动时listView会黑掉, 原因是,滚动时,列表里面的view重绘时,用的依 ...
- c++ 读写结构体到文件
可以使用fwrite()将一个结构体写入文件: fwrite(&some_struct,sizeof somestruct,1,fp);对应的fread函数可以再把它读出来,此处fwrite ...
- scrum心得和团队作业
一.学习scrum心得 敏捷的介绍 最近上课我们了解到了敏捷,很多人开始谈论敏捷开发.研究敏捷开发,那么究竟什么才是敏捷开发呢? 简单的说,敏捷开发是一种以人为核心.迭代.循序渐进的开发方法.在敏捷开 ...
- 初学scrum及首次团队开发
一.初学scrum 1.什么是scrum Scrum在英语的意思是橄榄球里的争球.而在这里Scrum是一种迭代式增量软件开发过程,经常性的被用于敏捷软件开发.Scrum包括了一系列实践和预定义角色的过 ...