翻译人员: 铁锚

翻译时间: 2013年11月15日

原文链接: Java
equals() and hashCode() Contract

图1

Java所有对象的超类 java.lang.Object 有两个非常重要的方法定义:

public boolean equals(Object obj)
public int hashCode()

实践证明这两个方法是非常重要的,特别是用Map存储用户自定义对象时.然而,有些高级开发者也不一定知道如何合适的使用它们。

本文先用示例演示如何使用它们,然后解释 equals()方法和hashCode是如何协同工作.

1. 错误使用方式

下面是一个常见的错误用法:

import java.util.HashMap;

public class Apple {
    private String color;

    public Apple(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if (!(obj instanceof Apple))
            return false;
        if (obj == this)
            return true;
        return this.color == ((Apple) obj).color;
    }

    public static void main(String[] args) {
        Apple a1 = new Apple("green");
        Apple a2 = new Apple("red");

        //hashMap stores apple type and its quantity
        HashMap<Apple, Integer> m = new HashMap<Apple, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Apple("green")));
    }
}

在此示例中,hashMap 已经保存了一个绿色的Apple对象,但想(通过程序中的方式)从map获取此对象时,apple 对象并未被找到.

上述代码的输出结果是: null. 但通过断点调试,可以确定此对象已经存在于hashMap中,截图如下:

图2

2. 此问题由hashCode()引起

问题的原因是没有重写"hashCode()"方法.

equals()方法与hashCode()的通用协定是:

2.1 如果两个对象相等(equal),那么必须拥有相同的哈希码(hash code)

2.2 即使两个对象有相同的哈希值(hash code),他们不一定相等.



Map的核心思想就是可以比线性查找更快. 通过散列值(hash)作为键(key)来定位对象的过程分为两步:

在Map内部,存储着一个顶层数组,顶层数组的每个元素指向其他的数组,查找或存储的时候,先根据key对象的hashCode()值计算出数组的索引,然后到这个索引找到所指向的第二层线性数组,使用equals方法来比较是否有相应的值(以返回或者存储).

Object类中的hashCode()默认为每个对象返回不同的int值,因此在上面的例子中,两个相等(equal)的对象,返回了不同的hashCode值.

解决方法是为此类添加hashCode方法,比如,使用color字符串的长度作为示范:

public int hashCode(){
    // 此种实现,要求 color值定以后就不得修改
    // 否则同一个物理对象,前后有两个不同的hashCode,逻辑上就是错的。
    return this.color.length();
}

相关文章:

  1. Java中Set的contains()方法
  2. HashMap
    vs. TreeMap vs. Hashtable vs. LinkedHashMap
  3. Top
    8 Diagrams for Understanding Java
  4. Yet
    Another “Java Passes By Reference or By Value”?

equals()与hashCode()方法协作约定的更多相关文章

  1. 探索equals()和hashCode()方法

    探索equals()和hashCode()方法 在根类Object中,实现了equals()和hashCode()这两个方法,默认: equals()是对两个对象的地址值进行的比较(即比较引用是否相同 ...

  2. 如何编写出高质量的 equals 和 hashcode 方法?

    什么是 equals 和 hashcode 方法? 这要从 Object 类开始说起,我们知道 Object 类是 Java 的超类,每个类都直接或者间接的继承了 Object 类,在 Object ...

  3. 关于equals()和hashcode()的一些约定

    本文章主要讨论和回答一下几个问题: equals()的四大特性 equals()和hashcode()之间的关系,为什么我们经常说这两个方法要么都重写,要么都不重写? HashMap.HashSet等 ...

  4. Java中的equals和hashCode方法

    本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...

  5. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  6. Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)

    Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例  原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...

  7. 【转】Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例

    原文地址:http://www.cnblogs.com/luankun0214/p/4421770.html 感谢网友的分享,记录下来只为学习. 1.重写equals方法实例   部分代码参考http ...

  8. java集合(3)- Java中的equals和hashCode方法详解

    参考:http://blog.csdn.net/jiangwei0910410003/article/details/22739953 Java中的equals方法和hashCode方法是Object ...

  9. java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问

    本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...

随机推荐

  1. Docker命令查询

    基本语法 docker [OPTIONS] COMMAND [arg...] 一般来说,Docker 命令可以用来管理 daemon,或者通过 CLI 命令管理镜像和容器.可以通过 man docke ...

  2. Dynamics 365 Online 试用账号申请方式

    专人整理的申请方式PPT,这里转载给大家,下载地址

  3. Android Studio精彩案例(六)《使用一个Demo涵盖补间动画所有知识》

    转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 元旦假期里,闲的无事,看到美团加载数据的动画,就突想写个Demo把动画知识集成一下.后来想了想,还是直接用一个Demo来把所有动画知识 ...

  4. Android Studio精彩案例(五)《JSMS短信验证码功能实现》

    转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 很多应用刚打开的时候,让我们输入手机号,通过短信验证码来登录该应用.那么,这个场景是怎么实现的呢?其实是很多开放平台提供了短信验证功能 ...

  5. MFC误报内存泄露的修复

    在debug状态退出程序的时候,VS会在输出窗口列出可能的内存泄露的地方. MFC中使用DEBUG_NEW能够更方便的定位泄露的地点.但假如MFC的dll释放""过早"& ...

  6. 好IT男不能“淫”-谈IT人员目前普遍存在的“A情绪”

    <如果当道德无法约束你的时候...那么就让对疾病的恐惧来制约你吧> 前言 在写这篇文章前我的心情无比的沉重.几次提笔欲写,几次又未能完成,可是最终让我"奋笔疾书"的原因 ...

  7. ZooKeeper之(一)ZooKeeper是什么

    1.1 产生背景 当今是个分布式.集群.云计算等名词满天飞的时代.造成这种局面的一个重要因素就是,单一机器的处理能力已经不能满足我们的需求,不得不采用由多台机器组成的服务集群.服务集群对外提供服务的过 ...

  8. linux 服务器网络有关的内核参数

    几乎所有的内核模块,包括内核核心模块和驱动程序,都在/proc/sys 文件系统下提供了某些配置文件以提供用户调整模块的属性和行为.通常一个配置文件对应一个内核参数,文件名就是参数的名字,文件的内容是 ...

  9. 02_3中方式的反射,通过Class.forName获得Class对象,通过类.class获得字节码对象,通过类实例.getClass()的方式获得Class对象

     反射中加载类: Java中有一个Class类用于代表某一个类的字节码 .class文件    对应Class //1 加载类 // java中Class代表一个类,但是到底代表哪个类要明确指出 ...

  10. 14 ListFragment 代码案例

    MainActivity.java: package com.qf.day14_fragment_demo9_list; import android.os.Bundle; import androi ...