java的hashcode(结合hashset讲解)
equals()跟hashcode()都可以用来比较对象。hashcode通过不同对象有不同的散列码来比较两个对象。
hashcode方法把对象放到一个对象容器进行查找,算法好坏直接影响容器的存取效率。
HashCode() is explicitly used in methods where hash functions are used, like hashTable() etc.
One should always override hashCode() when overriding equals(). Unexpected behaviour will occur if you don't do so.
HashCode() should have the same value whenever equals() returns true.
Java中的集合(Collection)有两类,一类是List,再有一类是Set。list有序,可重复;set无序不重复。
判断两个元素是否重复?
equals方法,在集合中逐一取出元素与指定查询元素对比,有则返回true;遍历完没有,则返回false。
但如果集合太大,不能遍历,则需要使用hashcode()。
hashcode()是一个函数,通过计算将每个元素直接映射到存储位置上,如果无,则存储,如果存在则比较,相同,则不存;不同,则利用冲突方案解决(或者利用另一中方法另存一个位置,或者直接做链表)。
equals()和hashcode()这两个方法都是从object类中继承过来的。
equals()方法在object类中定义如下:
public boolean equals(Object obj) {
return (this == obj);
}
Integer、 Double等类都覆盖了hashcode()方法,如String类中定义的hashcode()方法如下:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
String的API中解释: Returns a hash code for this string. The hash code for a String object is computed as
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
返回值int为位置,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希码为 0。)
hashcode()最典型的应用是在hashset中,其与equal()的关系在hashset也应用的最明显。
(hashset是set类的扩展,其内部是使用HashMap 实现,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象参见:http://blog.csdn.net/longshenlmj/article/details/11907089和http://alex09.iteye.com/blog/539549)
当要存储一个元素时,先根据特定hash函数计算hashcode码,再除hashset整个表的长度,就得出了位置,再看该位置上的表中是否有相同元素(利用equal函数判断相同),没有,则存;有,则不存(不重复插入相同元素)。
Java默认的散列表(hash表单元长度)的大小全部都是2的幂,初始值为16(2的4次幂)。假如这16条链表中的75%链接有数据的时候,则加载因子达到默认的0.75。则HahSet重新散列(hash),即删掉后重新开辟一个散列单元大小为32(2的5次幂)的表,并重新计算各个数据的存储位置。以此类推下去.....
举例:
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class Name {
private String first;
private String last;
public Name(String first, String last) {
this.first = first;
this.last = last;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o.getClass() == Name.class) {
Name n = (Name) o;
return n.first.equals(first) && n.last.equals(last);
}
return false;
}
}
public class hashsettestforall {
public static void main(String[] args) {
Set<Name> s = new HashSet<Name>();
s.add(new Name("abc", "123"));
System.out.println((new Name("abc", "123")).hashCode());
System.out.println(s.hashCode());
System.out.println(s.contains(new Name("abc", "123")));
}
}
此段代码,一般看可能认为输出为true。但是由于Name类只重写了equals(),hashcode没有被重写,加入元素时使用的hashcode()是继承于set<-collection<-object的,所以计算的hashcode值不同,存储位置不同,则认为元素不相同,输出false。
输出结果为:
482535999
1104499981
false
看出hashcode不同,位置不同。所以一般设计hashcode的,要求hashCode方法和equals方法同时覆盖。
注意1:
equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,hashcode()不知道是否相等。(也就是说equals()方法不相等的两个对象,hashcode()有可能相等)。而hashcode()不等,则equals()一定不等;同样hashcode()相等,equals()可能相等,也可能不等。
所以,上述代码覆盖hashcode()函数:
public int hashCode()
{ return first.hashCode();
}
用成员first计算hashcode,则可保证first相同的对象,存储位置相同。再用equals比较就知道是否相同。
这里需要注意2:
当一个对象存进hashset集合中以后,其包含参与计算哈希值的字段就必须固定,不能被修改。否则,hashset的哈希值就不同了,这种情况下,即使使用contains方法检索该对象时,也将返回false。这会导致无法从hashset集合中删除对象,造成内存泄露。
总结如下:
(1)只有类的实例对象要被采用哈希法存储和检索时,如hashset,这个类才需要按要求覆盖hashCode方法,通常要求hashCode方法和equals方法一并被同时覆盖。
(2)equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,hashcode()不知道是否相等。(也就是说equals()方法不相等的两个对象,hashcode()有可能相等)。而hashcode()不等,则equals()一定不等;同样hashcode()相等,equals()可能相等,也可能不等。
(3) 当一个对象存进hashset集合中以后,其包含参与计算哈希值的字段就必须固定,不能被修改。否则,hashset的哈希值就不同了,这种情况下,即使使用contains方法检索该对象时,也将返回false。这会导致无法从hashset集合中删除对象,造成内存泄露。
另外,
hashmap的hashcode()如下:
public final int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
api解释如下:
Returns the hash code value for this map entry. The hash code of a map entry
e is defined to be:
(e.getKey()==null ? 0 : e.getKey().hashCode()) ^
(e.getValue()==null ? 0 : e.getValue().hashCode())
This ensures that e1.equals(e2) implies that e1.hashCode()==e2.hashCode() for any two Entriese1 and
e2, as required by the general contract of Object.hashCode.
- Returns:
- the hash code value for this map entry
而
int
java.lang.Object.hashCode()也有具体解释,截取部分如下:
Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided byjava.util.Hashtable.
其他省略。
java的hashcode(结合hashset讲解)的更多相关文章
- Java set接口之HashSet集合原理讲解
Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...
- java中hashcode()和equals()的详解
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...
- java集合-hashCode
hashCode 的作用 在 Java 集合中有两类,一类是 List,一类是 Set 他们之间的区别就在于 List 集合中的元素师有序的,且可以重复,而 Set 集合中元素是无序不可重复的.对于 ...
- Java中hashCode的作用
转 http://blog.csdn.net/fenglibing/article/details/8905007 Java中hashCode的作用 2013-05-09 13:54 64351人阅 ...
- Java 集合系列 16 HashSet
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java的HashCode,Equal和==
----------------------------------------以下是分割线---------------------------------------- 我们都知道Java语言是完 ...
- [Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>
这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包.本文仅作几个类的浅度解析. (本文基于JDK1.7,源码来自openjdk1.7.) ├── Collection │ ├── ...
- == 和 equals,equals 与 hashcode,HashSet 和 HashMap,HashMap 和 Hashtable
一:== 和 equals == 比较引用的地址equals 比较引用的内容 (Object 类本身除外) String obj1 = new String("xyz"); Str ...
- Java中hashcode的理解
Java中hashcode的理解 原文链接http://blog.csdn.net/chinayuan/article/details/3345559 怎样理解hashCode的作用: 以 java. ...
- Java集合框架之HashSet浅析
Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...
随机推荐
- [转]关于OpenGL的绘制上下文
[转]关于OpenGL的绘制上下文 本文转自(http://www.cnblogs.com/Liuwq/p/5444641.html) 什么是绘制上下文(Rendering Context) 初学Op ...
- MySQL 排序
MySQL 排序 我们知道从MySQL表中使用SQL SELECT 语句来读取数据. 如果我们需要对读取的数据进行排序,我们就可以使用MySQL的 ORDER BY 子句来设定你想按哪个字段哪中方式来 ...
- Bootstrap3 表单-被支持的控件:输入框
输入框包括大部分表单控件.文本输入域控件,还支持所有 HTML5 类型的输入控件: text.password.datetime.datetime-local.date.month.time.week ...
- 对 /dev/shm 认识
一./dev/shm理论 /dev/shm/是linux下一个非常有用的目录,因为这个目录不在硬盘上,而是在内存里.因此在linux下,就不需要大费周折去建 ramdisk,直接使用/dev/shm/ ...
- log file sync 因为数据线有问题而造成高等侍的表现
这是3月份某客户的情况,原因是服务器硬件故障后进行更换之后,业务翻译偶尔出现提交缓慢的情况.我们先来看下awr的情况. 我们可以看到,该系统的load profile信息其实并不高,每秒才21个tra ...
- Android图表库MPAndroidChart(三)——双重轴线形图的实现,这次就so easy了
Android图表库MPAndroidChart(三)--双重轴线形图的实现,这次就so easy了 在学习本课程之前我建议先把我之前的博客看完,这样对整体的流程有一个大致的了解 Android图表库 ...
- OpenCV+python 人脸识别
首先给大家推荐一本书:机器学习算法原理与编程实践 本文内容全部转载于书中,相当于一个读书笔记了吧 绪论 1992年麻省理工学院通过实验对比了基于结构特征的方法与基于模版匹配的方法,发现模版匹配的方法要 ...
- T-SQL注意事项(1)——SET NOCOUNT ON的去与留
前言 用了一段时间T-SQL之后,哪怕自己没用过,也多多少少看过SSMS中的SET NOCOUNT ON命令,很多性能优化文章中都有提到这个东西,它们建议尽可能使用这个命令减少网络传输的压力,那么今天 ...
- Nginx的负载均衡 - 最少连接 (least_conn)
Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 算法介绍 我们知道轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同. 这有个前提,就是每个请 ...
- Scala actor的使用
Actor 为什么需要Actor? Actor的本质即万物皆Actor, Actor之间只有发送消息这一种通信方式.例如,无论是管理员让工作者干活,还是工作者把成果交还给管理员,它们之间也要通过发送消 ...