java的hashcode

来源:互联网 发布:软件开发学费多少 编辑:程序博客网 时间:2024/06/14 17:47

一、hashcode简介

hashcode是Object里定义的一个方法public native int hashCode();,我们看一下官方给出的注释:

Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by java.util.HashMap. The general contract of hashCode is: •Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. •If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. •It is not required that if two objects are unequal according to the java.lang.Object.equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables. As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

意思为:
为每个对象返回一个哈希码值,支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

hashcode的通常的协议是:

  • 在java应用程序执行期间,无论何时多次调用同一对象hashCode方法时,必须返回相同的整数,前提是对象上equals比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果两个对象通过equals方法判定为相等,那么调用这两个对象的hashCode方法所返回的值也一定相同。
  • 如果两个对象通过equals方法判定为不相等,则调用这两个对象的hashCode方法并不一定返回相同的hashCode。但是,程序员应该意识到两个不相等的对象产生不一样的hash值可以提高哈希表的性能。

事实上,由object定义的hashCode方法在不同的对象中也返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是java编程语言不需要实现这个技巧。)

二、hashcode方法的作用

什么是哈希表

我们先来介绍一下散列表(哈希表),散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表(摘自百度百科-哈希表)。哈希表即是通过给定任意的关键字key,通过hash函数计算出hash地址,从而快速的拿到该关键字在表中所在的存储位置。

为什么用哈希表

哈希表不同于链表、树等数据结构,它提供快速的插入和查找操作,它不必将关键字与表中所有的记录进行一一比较去找到关键字所在位置,而是直接通过这个关键字直接定位到该记录在表中的位置,这样时间复杂度降到O(1)。 举个例子,我在hashmap中存放了一个{key:man,value:zhangsan}的记录,当然表中还有其他很多记录(几百万条),那么我在获取这个key为man的元素时如果遍历整个集合的key,知道找到与之相等的key为止,这样做的确是达到了我们的功能,但是这样效率上就低了不少,哈希表的作用就是,当我们提供了man这个key时,可以直接通过hash函数得到hashcode值,再通过这个值可以直接定位到这个元素所在的位置,这样效率上对比起来是不是提升了非常多?

说到hashCode方法,就不得不把equals方法也提出来,equals方法的作用是:如果两个为基本数据类型,则只比较值;如果是两个对象,则比较它们引用所在的地址是否指向同一地址,与”==”运算符一样,当判断对象时用于判断两个对象是否为同一对象(不包含重写了equals方法的对象)。

  • 对于equals两个相等的对象,它们的hashCode()返回值一定相等
    以hashset为例,我们知道set集合是不包含相同的元素的,在存入对象时它的步骤为,首先获取该对象的hashcode值,经过hash函数算法找到它在哈希表中的存放位置,如果这个位置为空,则将对象放入;如果不为空,则还需要使用equals方法与里面的对象进行相等判断(因为不止这个对象才会产生这个hashcode值),如果都不相等,则根据hash冲突算法把该对象插入到其他位置,如果相等,则表示这个对象已经在集合内。java规定对hashset判断是否重复对象是通过equals方法来判断的,如果两个对象equals相等,而它们的hashCode()返回值不相等,则会在set集合内插入两个equals相等的对象,这是不允许的,所以对于equals两个相等的对象,它们的hashCode()返回值一定相等。

  • 重写equals方法时,同时必须重写hashCode方法
    这里举个例子,查看以下代码

class Person {    private String name;    private int age;    public Person(String name, int age) {        super();        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Person other = (Person) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }}如果只重写了equals方法,当name和age都相等的时则判断两个对象相等,则会存在问题Person tom1 = new Person("tom", 20); Person tom2 = new Person("tom", 20); System.out.println(tom1.equals(tom2));在重写了equals方法后,这两个对象就是相等的,但是因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便两个equals相等的两个对象,它们的hashcode值也是不相等的,这违背了上述第一点,在放入hashset这样的集合时就会出现问题。所以在重写了equals方法的同时也一定要重写hashcode方法。

声明:本文是由本人通过学习而写出的,文中不保证所有描述全是正确的,如果错误之处还请指出,一起探讨学习。

0 0