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 ...
随机推荐
- 20160218.CCPP体系详解(0028天)
程序片段(01):加法.c 内容概要:字符串计算表达式 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <st ...
- android M Launcher之数据库实现
前面一系列文章我们分析了LauncherModel的工作过程,它会把数据绑定到桌面上.从今天开始我们来分析下Launcher的数据来源即Launcher数据库的实现. 一个完整的数据库实现都应该包括两 ...
- python模块:网络协议和支持
python模块:网络协议和支持 webbrowser 调用浏览器显示html文件 webbrowser.open('map.html') [webbrowser - Convenient Web-b ...
- Android开发之Path类使用详解,自绘各种各样的图形!
玩过自定义View的小伙伴都知道,在View的绘制过程中,有一个类叫做Path,Path可以帮助我们实现很多自定义形状的View,特别是配合xfermode属性来使用的时候.OK,那我们今天就来看看P ...
- [Mysql]由Data truncated for column联想到的sql_mode配置
系统日志中出现了 ata truncated for column 'agent' at row 1 mysql出现这个问题的原因,无非就是字符集设置 或者是 字段过长导致的. mysql在初始化的时 ...
- Java基本语法-----java变量
1.变量的概述 用于存储可变数据的容器. 2.变量存在的意义 计算机主要用于处理生活中的数据,由于生活中存在大量的可变数据,那么计算机就必须具备存储可变数据的能力. 比如: 1.时间每一秒都在发生变化 ...
- Android事件分发回传机制
转载本博客,请注明出处:点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52489026 之前以一个爷爷给孙子分馒头的故事,初探了安 ...
- memcached实战系列(五)Memcached: List all keys 查询所有的key
memcached可能当时设计的时候就把它定位为内存性的kv结构的缓存系统.所以没有持久化到磁盘的命令,也没有查看所有key的值得命令.可能觉得没必要吧,你要是缓存1个G内存的数据,自己都头大,还敢看 ...
- spring @Qualifier注解使用
@Autowired是根据类型进行自动装配的.如果当Spring上下文中存在多个UserDao类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在U ...
- 6.1、Android Studio的Android Monitor概览
Android Monitor帮助你监测你的应用的性能,以帮助你合理的进行优化,调试,提升.如下功能: 1. Log消息,系统定义的或者开发者定义的. 2. 内存,CPU和GPU使用情况. 3. 网络 ...