`
mazhiyuan
  • 浏览: 64295 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

对hashset与hashmap中equals和hashcode的思考

阅读更多

偶然看了f543711700大大写的关于“对java如何判断HashSet和HashMap中相同元素的研究”一文(连接如下)

http://f543711700.iteye.com/blog/800929

对之中提出的“equals返回真,则hashcode值相等”一度抱有怀疑态度,因为之前在实际的编码工作中,确实覆盖了object的equals方法,但从未认真思考hashcode的值是否也相等。

 

为了搞清楚这个问题,首先在JDK源码中看看object是怎么定义equals方法的吧:

 

    Note that it is generally necessary to override the <tt>hashCode</tt>
    method whenever this method is overridden, so as to maintain the
    general contract for the <tt>hashCode</tt> method, which states
    that equal objects must have equal hash codes. 

public boolean equals(Object obj) {
	return (this == obj);
    }

 

 

 

看的出来在object中equals的具体实现就是==,这也是为什么要覆盖这个方法的原因之一,注释的那一段,说明若要覆盖equals方法,同时也要覆盖hashcode方法。力求做到相同的对象有着相同hashcode值。

 

在hashmap中调用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;
    }

 在判断是否已经存在这样一个键时,源码里既判断了hashcode的值也使用了equals方法,并且在&&后面的判断中同样也是使用了这两者,只不过是或得关系了。

若是存在这样一个键,会将原来的value覆盖,这就是为什么f543711700文中第二个测试代码size会返回1,因为第一个k-v对已经被第二个k-v对覆盖了。

 

通过与其他同事的交流,只要没有涉及hash相关的代码倒是不用都覆盖hashcode方法,毕竟使用在这种情况下使用它的机会也很少,但是在涉及hash相关的地方一定要覆盖,确保它与equals同步。

 

拿hashset举一个例子吧:

PS:这个例子来源自bepatient大大,写的很恰当,我就借来了

原文链接:http://bepatient.iteye.com/blog/702819

HashSet是一个无序不可以重复储存的集合。HashSet是靠hashcode方法,如果对应的两个对象所返回的hashcode方法的值是相等的,则表明该两个对象“相等”。所以一般情况下,用户需要对要储存到HashSet的对象所在的类重写hashcode方法,而不是用继承自Object的hashcode方法,因为Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数(这一般是通过将该对象的内部地址转换成一个整数来实现的),一般不符合用户的需求。
要想在HashSet中知道对象的位置,就要先计算该对象的hashcode,然后与散列表的列表的总数取余,所得结果就是保存这个元素的列表的索引。
当一个对象被储存进HashSet集合后,就不能再修改这个对象中的那些参与计算hashcode值的属性了,否则对象修改后的hashcode与最初储存到HashSet的值不一致,在这种情况下,即使在contains方法中使用该对象的当前引用作为参数区HashSet集合中检索对象,也将返回不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
为什么会杀不了呢:因为,当集合调用remove方法的时候,会从对象得到hashcode,但是原先对象储存的时候所对应的hashcode不是现在的hashcode,所以定位的不是相同的对象,因此删除不了。
所谓内存泄露是指该对象已经不需要再用,但是一直占着内存空间。

示例代码:

package mm.testJava;
import java.util.*;
public class Person {
    
 private String str;
 private int age;
 
 public Person(){
  
 }
 
 public Person(String str,int age){
  this.str=str;
  this.age=age;
 }
 
 public void setName(String str){
  this.str=str;
 }
 
 public int hashCode(){
  int code;
  
  if(str=="p1") code = 1;
  else if(str=="p2") code = 2;
  else if(str=="p3") code = 3;
  else code = 4;
   
  return code;
 }
}

 

package mm.testJava;

import java.util.Collection;   
import java.util.Date;   
import java.util.HashSet;   
  
public class HashSetTest {   
    public static void main(String[] args) {   
        Collection c = new HashSet();   
  
        Person p1 = new Person("p1",23);   
        Person p2 = new Person("p2",23);   
        Person p3 = new Person("p3",23);   
        c.add(p1);   
        c.add(p2);   
        c.add(p3);   
        p1.setName("p4");   
        c.remove(p1);   
        System.out.println(c.size());//size的值依然是3   
    }   
}

 

 

分享到:
评论

相关推荐

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

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

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

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是两个非常重要的成员,尤其是在处理对象比较和集合操作时。这两个方法通常与`Object`类中的默认实现相关联,但为了在实际开发中实现正确的对象比较和哈希表操作...

    Java中HashSet和HashMap的区别_动力节点Java学院整理

    当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会...

    equals,hashcode,toString

    在Java编程语言中,`equals()`, `hashCode()` 和 `toString()` 是三个非常重要的方法,它们主要用于对象的比较、哈希存储以及打印对象信息。这三个方法是Java对象的基础特性,对于理解和开发高质量的Java程序至关...

    Java中的equals和hashCode方法详解1

    在Java编程语言中,`equals()`和`hashCode()`方法是对象的基本组成部分,它们主要用于对象的比较和存储。这两个方法在`java.lang.Object`类中定义,因此所有的Java类都默认继承了这两个方法。然而,根据具体的应用...

    Java容器集合(equals 和 hashCode+基础数据结构+ArrayList+Vector和LinkedList)

    其中,equals和hashCode方法是Java容器集合中两个非常重要的方法,本文将详细介绍这两个方法,并结合ArrayList、Vector和LinkedList三个常见的容器集合。 一、equals方法 equals方法是Java中用于比较两个对象是否...

    equals 和 hashCode两者效果分析详解.docx

    在Java编程语言中,`equals()`和`hashCode()`方法是两个非常重要的概念,尤其是在处理对象比较和容器(如HashMap和HashSet)操作时。这两个方法在Java的类库中有着核心地位,尤其是对于类实例的比较和存储。接下来,...

    Java基础加强_ArrayList_HashSet的比较及Hashcode分析

    在自定义类中,为了使对象能被HashSet或HashMap正确处理,通常需要重写hashCode()和equals()方法,确保它们遵循一致性原则。 在ArrayList和HashSet的比较中,我们可以总结以下几点: 1. 数据结构:ArrayList基于...

    treemap treeset hashset hashmap 简要介绍

    对于`HashMap`,尽管`Student`类的`equals()`和`hashCode()`方法未正确实现,但是由于`HashMap`使用的是对象引用作为键,所以每个调用`put()`方法都会覆盖之前的值,最终`map`中只会有最后一个键值对。 综上所述,...

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

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

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

    例如,在Hashtable、HashMap、HashSet、LinkedHashMap等容器中,我们需要重写hashcode()方法,使其生成对象的哈希码,以便于快速地查找和比较对象。 compareTo()方法是Comparable接口中的一个方法,它用于比较两个...

    Java_重写equals()和hashCode()

    这两个方法与对象的相等性比较和哈希表(如HashMap、HashSet)的运作紧密相关。这篇博客将深入探讨这两个方法的重写规则和应用场景。 首先,`equals()` 方法是Object类中的一个基础方法,用于比较两个对象是否相等...

    java中hashcode()和equals()方法详解

    为了确保集合类如`HashSet`和`HashMap`的正确行为,`hashCode()`和`equals()`之间必须满足以下条件: - 如果`equals()`方法判定两个对象相等,则这两个对象的`hashCode()`值必须相同。 - 相反,如果两个对象的`...

    HashMap底层实现原理HashMap与HashTable区别HashMap与HashSet区别.docx

    HashMap与HashTable的主要区别在于线程安全性和对null值的支持。HashMap是非同步的,意味着在多线程环境中,如果不进行适当的同步控制,可能会导致数据不一致。而HashTable是同步的,因此它在多线程环境下的安全性更...

    HashSet和HashMap的区别_动力节点Java学院整理

    HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有...

    解析Java对象的equals()和hashCode()的使用

    在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们的默认设计就可以了。但是在一些情况下,这两个...

    hashcode()和equals()

    在Java编程语言中,`hashCode()` 和 `equals()` 方法是两个非常重要的概念,尤其是在处理对象比较和哈希表(如 `HashMap` 或 `HashSet`)时。这两个方法来源于 `Object` 类,是所有Java类的基类,因此,每个自定义类...

    Java中的equals()和hashCode()契约Ja

    在Java编程语言中,`equals()`和`hashCode()`方法是两个至关重要的概念,它们与对象的比较和哈希表操作紧密相关。理解这两个方法的工作原理及其契约是成为一名熟练的Java开发者所必需的。 首先,`equals()`方法是...

    java 中HashMap、HashSet、TreeMap、TreeSet判断元素相同的几种方法比较

    在Java编程中,HashMap、HashSet、TreeMap和TreeSet是四种常见的集合类,它们各自有特定的用途和内部实现机制。这些数据结构用于存储和管理数据,其中HashMap和HashSet是基于哈希表实现的,而TreeMap和TreeSet则是...

    java集合——Java中的equals和hashCode方法详解

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中定义的基本方法,所有类都默认继承自Object类,因此每个Java对象都有这两个方法。这两个方法在处理集合类,尤其是Set接口的实现(如HashSet)时起着...

Global site tag (gtag.js) - Google Analytics