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 ...
随机推荐
- Flume 读取RabbitMq消息队列消息,并将消息写入kafka
首先是关于flume的基础介绍 组件名称 功能介绍 Agent代理 使用JVM 运行Flume.每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks. Client ...
- JAVA不可变类(immutable)机制与String的不可变性
一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类, ...
- 关于java的Synchronized,你可能需要知道这些(下)
上一篇文章介绍了synchronized的基本使用方法和实现,在实现部分说明了synchronized的底层实现依赖系统互斥锁mutex,但是这个一个重型锁,竞争导致线程阻塞挂起,后续拿到锁后再恢复线 ...
- 【if...else】身高预测
每个做父母的都关心自己孩子成人后的身高,据有关生理卫生知识与数理统计分析表明,影响小孩成人后的身高的因素包括遗传.饮食习惯与体育锻炼等.小孩成人后的身高与其父母的身高和自身的性别密切相关.设faHei ...
- vue开发中v-for在Eslint的规则检查下出现:Elements in iteration expect to have 'v-bind:key' directives
在使用VScode编辑器vue开发过程中,v-for在Eslint的规则检查下出现报错:Elements in iteration expect to have 'v-bind:key' direct ...
- 用Matlab画直方图
简介 本文介绍如何使用matlab定制自己的直方图. 关键 使用Matlab的 bar() 函数创建柱状图 bar() 画的bin的高度跟数据相关 bar() 数据每一列一个group,有几列数据就画 ...
- miracl去除某些特殊信息
只需要在mirdef.h中增加定义 #define MR_STRIPPED_DOWN 即可在编译的时候,去掉错误信息 #define MIRACL 32 #define MR_LITTLE_ENDI ...
- 高通开发笔记---yukon worknote
点击打开链接 daily buildhttp://android-ci-platform.cnbj.sonyericsson.net/job/daily_build_jb-mr2-yukon/DL-C ...
- linux源码编译安装OpenCV
为了尽可能保证OpenCV的特性,使用OpenCV源码编译安装在linux上.先从安装其依赖项开始,以ubuntu 14.04.X为例讲解在Linux上源码编译安装OpenCV,其他linux版本可以 ...
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...