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/11907089http://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.

Specified by: hashCode() inEntry,
Overrides: hashCode() inObject
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讲解)的更多相关文章

  1. Java set接口之HashSet集合原理讲解

    Set接口 java.util.set接口继承自Collection接口,它与Collection接口中的方法基本一致, 并没有对 Collection接口进行功能上的扩充,只是比collection ...

  2. java中hashcode()和equals()的详解

    今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36). 1. 首先equals()和hashc ...

  3. java集合-hashCode

    hashCode 的作用 在 Java 集合中有两类,一类是 List,一类是 Set 他们之间的区别就在于 List 集合中的元素师有序的,且可以重复,而 Set 集合中元素是无序不可重复的.对于 ...

  4. Java中hashCode的作用

    转  http://blog.csdn.net/fenglibing/article/details/8905007 Java中hashCode的作用 2013-05-09 13:54 64351人阅 ...

  5. Java 集合系列 16 HashSet

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  6. Java的HashCode,Equal和==

    ----------------------------------------以下是分割线---------------------------------------- 我们都知道Java语言是完 ...

  7. [Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>

    这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包.本文仅作几个类的浅度解析. (本文基于JDK1.7,源码来自openjdk1.7.) ├── Collection │ ├── ...

  8. == 和 equals,equals 与 hashcode,HashSet 和 HashMap,HashMap 和 Hashtable

    一:== 和 equals == 比较引用的地址equals 比较引用的内容 (Object 类本身除外) String obj1 = new String("xyz"); Str ...

  9. Java中hashcode的理解

    Java中hashcode的理解 原文链接http://blog.csdn.net/chinayuan/article/details/3345559 怎样理解hashCode的作用: 以 java. ...

  10. Java集合框架之HashSet浅析

    Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...

随机推荐

  1. python笔记八(切片)

    一.切片 首先我们要记得在Python中可以用于切片的对象有 列表.元组.字符串. 切片操作就是直接从列表.元组或字符串中,选择出我们想要的内容,这些操作非常简洁实用. >>> L ...

  2. 利用百度接口进行人脸识别并保存人脸jpg文件

    利用百度接口进行人脸识别,根据返回的人脸location用opencv切割保存. # coding : UTF-8 from aip import AipFace import cv2 import ...

  3. 操作系统内核Hack:(四)内核雏形

    操作系统内核Hack:(四)内核雏形 在本系列的前一篇文章<操作系统内核Hack:(三)BootLoader制作>中,我们制作出了一个两阶段引导BootLoader,并进入了一个内核的空壳 ...

  4. 虚拟机克隆,并设置新的ip

    6.1克隆新的虚拟机 选中某个虚拟机-à右键à管理à克隆 选择下一步 选择下一步 点击完成 6.2修改主机名 [root@hadoop3 ~]# vim/etc/sysconfig/network 将 ...

  5. oh forever love~

    npm install -g forever forever start c9sdk/server.js --listen 0.0.0.0 --port 80 -a aa:111 -w ~ To el ...

  6. Make things beautiful again !

    在知乎有一个问题:如何让大脑休息放松? 我曾回答说:整理凌乱的文件夹(电脑的). 其实最近特别烦恼,似乎所有人都不按常理出牌,似乎所有事都不按套路发展.经营一个企业的压力,加上长期没有来自" ...

  7. Android简易实战教程--第三十五话《音乐播放》

    已经好几天不更新博客了,今天轻松一点模拟个简单的"音乐播放器".1分钟看完~ 整个简单布局,加几个控制按钮: <LinearLayout xmlns:android=&quo ...

  8. CountDownLatch使用

    分享牛原创,CountDownLatch类的使用,CountDownLatch是一个工具类,运行主线程开启子线程的时候,子线程还没有结束的时候,主线程可以一直等待,直到初始化的现成的计数器count为 ...

  9. 有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间。

    int findMaxDifBt2Nums(int* arr, int len) { int maxItem = arr[0], minItem = arr[0]; for (int i = 1; i ...

  10. nginx平台初识(一)

    众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧. nginx在启动后,在unix系统中会以daemon的方式 ...