`
feikiss
  • 浏览: 100012 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Effective java: 覆盖equals时总要覆盖hashCode 的探究

阅读更多
在Effective Java中的第九条说:覆盖equals总要覆盖hashCode。
“一个很常见的错误根源在于没有覆盖hashCode方法,在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。”
以下约定内容摘自Object规范[JavaSE6]:
1. 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
2. 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
3. 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
显然,如果没有覆盖hashCode,就会违反第二条关键约定。
以上为理论部分,以下为实际实践的尝试,显示hashCode的作用:
首先生成一个简单的Box类:
public final class Box {
	private int length;
	private int width;
	private int heigth;
	public Box(){
		
	}
	public Box(int length, int width, int heigth){
		this.length = length;
		this.width = width;
		this.heigth = heigth;
	}
	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		this.length = length;
	}
	public int getWidth() {
		return width;
	}
	public void setWidth(int width) {
		this.width = width;
	}
	public int getHeigth() {
		return heigth;
	}
	public void setHeigth(int heigth) {
		this.heigth = heigth;
	}
	
	@Override
	//重写equals方法。
	public boolean equals(Object o){
		if(o == this){
			return true;
		}else if(!(o instanceof Box)){
			return false;
		}else {
			Box boxtmp = (Box) o;
			return boxtmp.heigth == this.heigth 
				&& boxtmp.width == this.width
				&& boxtmp.length == this.length;
		}
	}
	
}

类Box中重写了equals方法。
然后写一个测试类:
iimport java.util.HashMap;

public class HashCodeAndEqualTest {
	public static void main(String[] args) {
		Map<Box, Integer> map = new HashMap<Box, Integer>();
		Box a = new Box(1,2,3);
		Box b = new Box(1,2,3);
		System.out.println("a == b :"+(a == b));
		System.out.println("a .equals(b):"+a .equals(b));
		map.put(a, 1);
		System.out.println(map.get(a));
		System.out.println(map.get(b));
		
	}
	
}

输出结果:
引用

a == b :false
a .equals(b):true
1
null

既然a.equals(b)都已经为true了,那为什么map.get(b)的返回值为null呢?map.get(b)的预期值应该和map.get(a)相等的,下面再在Box类中重写一个父类方法:hashCode():
@Override
public int hashCode(){
	int result = 0;
	result = result * 31 + length;
	result = result * 31 + heigth;
	result = result * 31 + width;
	return result;
}

然后再运行测试类,结果如下:
a == b :false
a .equals(b):true
1
1

为什么这次map.get(b) 和map.get(a)中的值相等了呢?这是因为重写了Box类中的hashCode方法,符合了第二天规定,如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
这样对象a和对象b的hash值是相等的。通俗一点儿讲, 如果a.hashCode () = b.hashCode()而且 a.euqals(b) (或 a==b) , 那么根据HashMap的算法,二者在同一个位置的,即HashMap认为只有符合以上条件,才认为a,和b是为同一key。
再深一点儿,可以参考HashMap中的get和put方法的实现,便可一探究竟。
HashMap中的get方法:
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        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.equals(k)))
                return e.value;
        }
        return null;
    }

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;
    }


if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
这一句已经大致解释了刚才的情况,更深一点儿可以探究一下hash算法的实现,挺有意思,不过时间有限,就先写到这里了~~
1
0
分享到:
评论

相关推荐

    Java_重写equals()和hashCode()

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们在很多场景下都发挥着至关重要的作用。这两个方法与对象的相等性比较和哈希表(如HashMap、HashSet)的运作紧密相关。这篇博客将深入...

    Java 覆盖equals时总要覆盖hashcode

    在Java编程中,当我们重写`equals()`方法时,通常也需要重写`hashCode()`方法。这是因为`equals()`和`hashCode()`方法在Java集合框架中扮演着重要的角色,特别是在使用`HashMap`、`HashSet`等基于哈希表的集合类时。...

    Java重写equals同时需要重写hashCode的代码说明

    Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.

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

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

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

    总的来说,理解并正确地重写 `equals()` 和 `hashCode()` 方法是Java编程中的基础技能,它有助于确保对象的比较和集合操作的正确性。在开发过程中,要时刻注意这两个方法的正确实现,以提高代码质量和可维护性。

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

    深入解析Java对象的equals()和hashCode()的使用 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们...

    Java理论与实践:hashCode()和equals()方法

    本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...

    Effective Java第三版1

    2. **hashCode方法**:当覆写`equals`时,必须同时覆写`hashCode`,以保持哈希表的正确性。 3. **toString方法**:为每个类提供一个有意义的字符串表示,方便调试和日志记录。 4. **clone方法**:`clone`方法的覆写...

    effective java 读书笔记

    - Item9:当覆盖equals时,必须同时覆盖hashcode,以保持哈希表的行为一致性。 - Item10:toString方法应返回对象状态的简洁表示,便于调试和日志记录。 - Item11:谨慎覆盖clone方法,因为它涉及到对象的深拷贝...

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

    在Java编程语言中,`hashCode()`和`equals()`方法是对象身份验证的关键组成部分,它们主要用于对象的比较和哈希表(如HashMap、HashSet等)的操作。理解这两个方法的工作原理对于编写高效和可靠的代码至关重要。 ...

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

    ### Java中`hashCode()`与`equals()`方法详解 #### 前言 在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将...

    Java中的equals和hashCode方法详解1

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

    关于hashCode()和equals()的本质区别和联系

    本文将详细介绍 hashCode() 和 equals() 的本质区别和联系,并探讨在创建 Java 类时如何定义这些方法。 hashCode() 方法 hashCode() 方法是 Object 类中的一个方法,它返回对象的哈希码值。哈希码值是一个整数,它...

    java 基础之(equals hashcode)

    在Java编程语言中,`equals()` 和 `hashCode()` 方法是两个非常重要的概念,尤其是在处理对象比较和哈希表(如 `HashMap` 和 `HashSet`)时。`equals()` 方法用于判断两个对象是否相等,而 `hashCode()` 方法则用于...

    hashcode和equals方法

    equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

    超详细_解释java_equals()与hashCode().pdf

    在Java编程中,`equals()`和`hashCode()`方法是Object类中的两个重要方法,它们在比较和处理对象时起着至关重要的作用。`equals()`方法用于判断两个对象是否相等,而`hashCode()`方法则与对象在哈希表中的存储位置...

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

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

    equals,hashcode,toString

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

    EffectiveJava:有效的 Java 示例

    - **覆盖 equals() 和 hashCode()**:当重写`equals()`时,必须同时重写`hashCode()`以保持一致性。 4. **异常处理** - **异常不应用于控制流**:异常应被视为异常情况的信号,而不是正常的程序流程控制手段。 -...

Global site tag (gtag.js) - Google Analytics