`
free9277
  • 浏览: 106600 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

重写Object中的hashCode方法

阅读更多

重写Object中的hashCode方法

    hashCode()用于返回调用该方法的对象的散列码值,此方法将返回整数形式的散列码值。

    在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址 值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了。一旦一个类重写equals()方法,通常也会重写 hashCode()方法。

    下面是重写hashCode()方法的约定的内容,来自Object规范[JavaSE6]:

    (1)、在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一直。

    (2)、如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

    (3)、如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。

     总之只有一个目的:hashCode方法要为"不相等的对象产生不相等的散列吗"。 下面我给出一个反例的代码。

import java.util.HashSet;

public class User {
    //用户名称
    private String userName;
    //用户密码
    private String password;
    
    public User(String userName, String password){
        this.userName = userName;
        this.password = password;
    }
    
    /**
     * 覆盖equals方法
     */
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }
        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }
        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }
        User user = (User)obj;
        return userName.equals(user.userName) && password.equals(user.password);
    }
    
    public String toString(){
        //System.out.println(userName.hashCode() + "      oooo");
        return userName + ":" + password;
    }
    
    public static void main(String[] args) {
        HashSet<User> set = new HashSet<User>();
        User user01 = new User("xiaom", "1");
        User user02 = new User("xiaom", "1");
        User user03 = new User("xiaoh", "2");
        User user04 = new User("xiaoj", "3");
        set.add(user01);
        set.add(user02);
        set.add(user03);
        set.add(user04);
        
        System.out.println("对象的内容" + "\t\t" + "对象的散列码");
        for(User user : set){
            System.out.println(user.toString() + "\t\t" + user.hashCode());
        }
    }

       输出的结果:

对象的内容   对象的散列码
xiaoj:3     17510567
xiaom:1     6413875
xiaoh:2     827574
xiaom:1     21174459

        这时候,我们可能期望只打印三个对象的值。由于我们重写了equals方法,所以user01对象和user02的对象是相等的。那么在hashSet集合中就应该只有三个元素。这是为什么呢?

    Java 中的集合类有两类:一类是List,一类是Set。前者允许集合内的元素可 以重复,后者则不允许集合中的元素可以重复。那么Java是如何判断集合中的元素是否重复呢?是通过对象中的equals()方法进行比较。但是,如果每 增加一个元素,都要进行一次equals比较。那么当集合中有很多元素时,就要进行很多次比较。也就是说,如果集合中有10000个元素,就得调用 10000次equals。这很明显降低了效率。于是,Java就采用了哈希表的原理,将数据依据指定的算法映射到一个地址上。这样一来,当集合要添加一 个元素时,只要调用该对象的hashCode方法,就可以找到指定的物理地址。如果该地址上没有元素,那么就将元素放在该地址上,不用再进行其他任何比较 了。如果该地址上有元素,那就调用equals方法进行比较,如果相同,则不需要添加改元素;如果不相同,就散列到其他地址。这样一来,实际调用 equals方法的次数就大大地减少了。

       我们再回过头看看刚刚的小例子。会出现那种错误,是因为我们没有重写hashCode方法。HashSet调用的是Object中的hashCode方法,而Object中的hashCode方法返回的是对象的地址值,所以HashSet认为user01对象与user02对象是不相等的,才在hashSet集合中出现4个对象。现在我们就来重写一下hashCode方法,看看效果如何,代码如下:

import java.util.HashSet;

public class User {
    //用户名称
    private String userName;
    //用户密码
    private String password;
    
    public User(String userName, String password){
        this.userName = userName;
        this.password = password;
    }
    
    /**
     * 覆盖equals方法
     */
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }
        //如果是同一个对象返回true,反之返回false
        if(this == obj){
            return true;
        }
        //判断是否类型相同
        if(this.getClass() != obj.getClass()){
            return false;
        }
        User user = (User)obj;
        return userName.equals(user.userName) && password.equals(user.password);
    }
    
    /**
     * 重写toString
     */
    public String toString(){
        return userName + ":" + password;
    }
    
    /**
     * 重写hashCode
     */
    public int hashCode(){
        int result = 17;
        result = 31 * result + userName.hashCode();
        result = 31 * result + password.hashCode();
        return result;
    }

    public static void main(String[] args) {
        HashSet<User> set = new HashSet<User>();
        User user01 = new User("xiaom", "1");
        User user02 = new User("xiaom", "1");
        User user03 = new User("xiaoh", "2");
        User user04 = new User("xiaoj", "3");
        
        set.add(user01);
        set.add(user02);
        set.add(user03);
        set.add(user04);
        System.out.println("对象的内容" + "\t\t" + "对象的散列码");
        for(User user : set){
            System.out.println(user.toString() + "\t\t" + user.hashCode());
        }
    }
} 

       输出的结果:

对象的内容     对象的散列码
xiaom:1        -759483308
xiaoh:2        -759483462
xiaoj:3        -759483399

         执行结果正确,收工。

 

    之前有发过一篇博文《重写Object中的equals方法》,有兴趣的朋友可以去看一看。http://free9277.iteye.com/blog/1832286

    由于本人能力有限,博客中的内容难免会有错误。请各位朋友评判指出,别让我一错再错,哈。非常感谢!

9
3
分享到:
评论
2 楼 WAMING5 2013-03-21  
引用
那么Java是如何判断集合中的元素是否重复呢?是通过对象中的equals()方法进行比较。但是,如果每 增加一个元素,都要进行一次equals比较。那么当集合中有很多元素时,就要进行很多次比较。也就是说,如果集合中有10000个元素,就得调用 10000次equals。这很明显降低了效率。于是,Java就采用了哈希表的原理,将数据依据指定的算法映射到一个地址上。这样一来,当集合要添加一 个元素时,只要调用该对象的hashCode方法,就可以找到指定的物理地址。

lz是否推敲过,假如我把Set放两个不同类型的对象并且hashcode都写死,写成一对比下呢?
看看JDK源码:
    public boolean add(E e) {
	return map.put(e, PRESENT)==null;
    }


当前对象作为了key
然后再看看put的实现
  public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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;
    }



e.hash == hash && ((k = e.key) == key || key.equals(k))
1 楼 panggezi 2013-03-20  
只对基于hash的集合是正确的,前一段时间有个关于TreeSet判重的帖子有讲过,仅仅override hash和equals对于TreeSet是没办法去重的。

相关推荐

    重写equals和hashcode方法_equals_重写equals和hashcode方法_

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...

    学习Object类——为什么要重写equeals和hashcode方法

    在 Java 编程语言中,Object 类是所有类的父类,但是在实际开发中,我们往往需要重写 Object 中的 equals 和 hashCode 方法,以便正确地比较对象的逻辑内容,而不是内存地址。下面我们将详细地解释为什么需要重写这...

    关于重写equals,hashcode以及compareTo方法!

    hashcode()方法是Object类中的另一个方法,它用于生成对象的哈希码。哈希码是一个整数,它可以用来标识对象的唯一性。在某些情况下,我们需要重写hashcode()方法,使其生成对象的哈希码,并且使其与equals()方法保持...

    关于Object中equals方法和hashCode方法判断的分析

    "关于Object中equals方法和hashCode方法判断的分析" 在 Java 中,Object 类提供了两个重要的方法:equals 方法和 hashCode 方法。这两个方法都是用于比较两个对象是否相等的,但它们的实现机理和作用域却有所不同。...

    Java重写equals及hashcode方法流程解析

    Java中的equals和hashCode方法是两个非常重要的方法,它们都是Object类中的方法。在实际开发中,正确地重写这两个方法对于确保程序的正确性和性能至关重要。下面,我们将详细地介绍Java重写equals及hashCode方法的...

    equals与hashCode方法讲解

    equals 方法和 hashCode 方法是 Java 语言中两个重要的方法,它们都是在 Object 类中定义的。equals 方法用于比较两个对象是否相等,而 hashCode 方法用于返回对象的哈希码。 在 Java 的 Object 类中,equals 方法...

    java中重写equals()方法的同时要重写hashcode()方法(详解)

    Java 中重写 equals() 方法的同时要重写 hashCode() 方法的重要性 在 Java 中,equals() 方法和 hashCode() 方法是两个紧密相关的方法,它们都是用于比较和标识对象的方法。equals() 方法用于比较两个对象的值是否...

    Java_重写equals()和hashCode()

    在重写 `hashCode()` 时,通常会基于 `equals()` 方法中用于比较对象相等性的属性来计算哈希码。例如,如果一个类有三个属性(a, b, c),则可以这样重写: ```java @Override public int hashCode() { int result...

    【面试】hashCode与equals两者之间的关系 / == 和equals / 为什么要重写equals方法 / 重写equals /hashcode方法 / 为什么要重写hashCode方法

    【面试】中提到的几个关键知识点集中在对象比较、equals()和hashCode()方法的使用以及它们之间的关系上。这些概念在Java编程中至关重要,特别是在处理集合类和比较对象时。 1、**hashCode与equals两者之间的关系**...

    为什么在重写 equals方法的同时必须重写 hashcode方法

    在 Java 中,`equals` 和 `hashCode` 方法是 Object 类中的两个重要方法,它们用于比较对象的相等性。默认情况下,`equals` 方法比较的是两个对象的引用,即是否指向内存中的同一个位置,而 `hashCode` 方法则返回...

    重写hashCode()和equals()方法详细介绍

    在Java编程中,`equals()` 和 `hashCode()` 方法是Object类中的两个重要方法,它们在处理对象相等性以及在哈希表(如HashSet、HashMap)中起到关键作用。当自定义类时,有时需要根据业务逻辑重写这两个方法以满足...

    java中为何重写equals时必须重写hashCode方法详解

    当我们在自定义类中重写 `equals()` 方法时,通常也需要重写 `hashCode()` 方法,这是为了遵循一些重要的原则和保证数据结构如 `HashMap`、`HashSet` 的正确行为。 首先,`equals()` 方法用于比较两个对象是否相等...

    why在重写equals时还必须重写hashcode方法分享

    在Java编程语言中,`equals()` 和 `hashCode()` 方法对于对象的比较和处理至关重要,特别是在集合框架中。这两个方法有着紧密的联系,因为它们在决定对象是否相等以及如何存储和检索对象时起到关键作用。 首先,让...

    java 序列化和重写 hashCode 的原因

    这两个方法在Java中的`Object`类中定义,但为了正确地比较对象并处理集合(如HashSet或HashMap)时,通常需要重写它们。`equals`方法用于比较两个对象是否相等,而`hashCode`方法返回对象的一个整数值,用于在哈希表...

    equals与hashCode在实际开发中的重写写法

    这两个方法通常与`Object`类中的默认实现相关联,但为了在实际开发中实现正确的对象比较和哈希表操作,我们往往需要重写它们。以下是对这两个方法的详细解释以及在实际开发中的应用。 `equals()` 方法: `equals()`...

    HashCode的用法详解

    如果我们不重写 hashCode(),那么对象的 hashCode 将会默认使用 Object 类中的 hashCode 方法,这样将会导致对象的存储位置不确定。 例如,如果我们有两个对象,它们的 hashCode 都是 1,那么它们将会被存放在同一...

    深入理解Java中HashCode方法

    在Java的所有类中,Object类是最顶层的父类,它定义了hashCode方法,该方法返回对象的hashCode值。hashCode方法的实现方式有多种,String类的hashCode方法就是一个典型的例子,它使用数学表达式s[0]*31^(n-1) + s[1]...

    重写equals方法

    第二种情况:对于采用哈希算法的集合,集合中对象必须重写 hashCode 方法,同时也要重写 equals 方法。这是因为哈希算法需要使用 hashCode 方法来计算对象的哈希值,而 equals 方法用于判断两个对象是否相等。 如何...

Global site tag (gtag.js) - Google Analytics