java中的hashcode
- hashcode的作用
对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。
当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值。实际上在HashMap的具体实现中会用一个table数组保存HashMap的对象,并且在table数组中存放的Entry对象中保存着存放对象的hash值。如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了。
更加通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。可以把hashcode简单的理解为对象存储的物理地址。
看一下HashMap的put()方法的源代码便可以很好的理解hashcode的作用了。
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
addEntry(hash, key, value, i);
return null;
}
put方法是用来向HashMap中添加新的元素,从put方法的具体实现可知,会先调用hashCode方法得到该元素的hashCode值,然后查看table中是否存在该hashCode值,如果存在则调用equals方法重新确定是否存在该元素,如果存在,则更新value值,否则将新的元素添加到HashMap中。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。
是否可以使用hashcode来判断对象是否相等呢?不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。
总结一下:
1、如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
2、如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
3、如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;
4、如果两个对象的hashcode值相等,则equals方法得到的结果未知。
- equals方法和hashCode方法
在设计一个类的时候,如果要重写equals方法,必须重写hashCode方法。
下面例子说明了hashcode()和equal()方法的作用:
public class Student {
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
Student student = (Student)obj;
return this.id==student.getId()&&this.name.equals(student.getName());
} }
public class Test {
public static void main(String[] args) {
Student s1 = new Student(18, "Jack"); System.out.println(s1.hashCode());
Map<Student, String> map = new HashMap<Student,String>(); map.put(s1, "1"); System.out.println(map.get(new Student(18, "Jack")));
}
}
这段代码输出的结果为null,就是因为重写equals方法的同时忘记重写hashCode方法。hashCode方法是将对象的存储地址进行映射。上面的s1和新生成的对象是两个不同的对象,存储地址不一样,所有输出null。
在HashMap的get()方法如下:
public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue();
}
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
} int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
可以看出在HashMap的get()方法中线比较hashcode值,如果hashcode相等,然后再进行比较equal()方法是否相等。
所以上述例子如果想输出1,必须要重写hashcode和equal方法,并且让equals方法和hashCode方法始终在逻辑上保持一致性。
总结一下:
1、在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。
2、如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。
3、如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。
另外,在设计hashCode方法和equals方法的时候,如果对象中的数据易变,则最好在equals方法和hashCode方法中不要依赖于该字段。如上面例子,学生添加一个年龄字段,如果hashcode依赖于年龄字段,那么每年对象的hashcode值是不一样的,所在HashMap的get方法就会取不到对象。
hashcode是用来区分对象是否相等的第一步,用hashcode可以减少比较时间。不能在对象加入到Hash容器中时修改对象属性,这样会导致内存泄漏(内存中的对象不能被正常清除掉)。Hash值只能针对hash容器来说。存放在Hash容器中的对象要认真设计hashcode()方法,减少hashcode冲突,这样其底层基本上是以数组实现的,否则就会退化为链表实现。
java中的hashcode的更多相关文章
- 浅谈Java中的hashcode方法
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据 ...
- 千万不要误用 java 中的 HashCode 方法
刚才debug追堆栈的时候发现一个很奇怪的问题 我用IE8和Google的浏览器访问同一个地址 Action的 scope="session" 也设置了 而且两个浏览器提交的参数m ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
- K:java中的hashCode和equals方法
hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...
- 【转】浅谈Java中的hashcode方法
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...
- Java中的hashcode方法
一.hashCode方法的作用 对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode.在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列 ...
- java 中的 hashcode
在Java的Object类中有一个方法: public native int hashCode(); 根据这个方法的声明可知,该方法返回一个int类型的数值,并且是本地方法,因此在Object类中并没 ...
- 浅谈Java中的hashcode方法(转)
原文链接:http://www.cnblogs.com/dolphin0520/p/3681042.html 浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地 ...
- 浅谈Java中的hashcode方法(转载)
哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据 ...
随机推荐
- 伪多项式时间算法Pseudo-polynomial Algorithms-----geeksforGeek 翻译
原创翻译加学习笔记,方便国人学习算法知识! 原文链接http://www.geeksforgeeks.org/pseudo-polynomial-in-algorithms/ 什么是伪多项式? 当一个 ...
- OpenCV的安装与系统环境变量
OpenCV的安装与系统环境变量 安装OpenCV本来是很简单的一件事,但配置却很麻烦.而且在配置过程中尤为重要的步骤就是系统环境变量的配置.我使用的是CodeBlick13.12与OpenCV1.0 ...
- ckplayer.js视频播放插件
网页中常见的功能就是播放视频,下面介绍的这个ckplayer.js既可以在pc端播放,也可以在手机网页上播放. 可调用flash也可以调用html5播放器: <div id="a1&q ...
- unity3d Aniso Level 摄像机近地面清楚,远地面模糊
设置方法 选中贴图 在属性面板,拖动Aniso Level的值从0~9改变,值越大贴图越清晰,但是消耗也变大,文档说会造成显卡消耗,一般只用在地面上,其他地方没必要 遇到的问题 但是打包到Ipod上面 ...
- Jenkins学习一:Jenkins是什么?
文章转载:http://www.cnblogs.com/zz0412/tag/jenkins/default.html?page=1 第一章 Jenkins是什么? Jenkins 是一个可扩展的持续 ...
- 获取本机的IP地址(局域网)与主机名称
编写内容保存为bat @echo off &setlocal enabledelayedexpansion Rem '/*========获取本机的IP地址(局域网)=========*/ e ...
- mysql怎么查询前10条数据?
mysql 没有top的用法.取而代之的是limit语法为:limit m,n省略n就可以得到你要的效果了. select * from table1 order by column desc li ...
- 承香墨影 Android--Matrix图片变换处理
承香墨影 Android--Matrix图片变换处理 前言 本篇博客主要讲解一下如何处理对一个Bitmap对象进行处理,包括:缩放.旋转.位移.倾斜等.在最后将以一个简单的Demo来演示图片特效的变换 ...
- msg url
- C# 类型运算符重载在类继承中的调用测试
这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA { } class CB : CA{ } class CC : CB{ } } void Test(CA oa){//CATest ...