`
qqdwll
  • 浏览: 131232 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java 实现 hashCode 方法

    博客分类:
  • Java
阅读更多
原文 http://www.javapractices.com/topic/TopicAction.do;jsessionid=8D0BB2D9061334756DC17A10A4FB5F71?Id=28

Implementing hashCode :

    * if a class overrides equals, it must override hashCode
    * when they are both overridden, equals and hashCode must use the same set of fields
    * if two objects are equal, then their hashCode values must be equal as well
    * if the object is immutable, then hashCode is a candidate for caching and lazy initialization

It is a popular misconception that hashCode provides a unique identifier for an object. It does not.

Example

The following utility class allows simple construction of an effective hashCode method. It is based on the recommendations of Effective Java, by Joshua Bloch.

import java.lang.reflect.Array;

/**
* Collected methods which allow easy implementation of <code>hashCode</code>.
*
* Example use case:
* <pre>
*  public int hashCode(){
*    int result = HashCodeUtil.SEED;
*    //collect the contributions of various fields
*    result = HashCodeUtil.hash(result, fPrimitive);
*    result = HashCodeUtil.hash(result, fObject);
*    result = HashCodeUtil.hash(result, fArray);
*    return result;
*  }
* </pre>
*/
public final class HashCodeUtil {

  /**
  * An initial value for a <code>hashCode</code>, to which is added contributions
  * from fields. Using a non-zero value decreases collisons of <code>hashCode</code>
  * values.
  */
  public static final int SEED = 23;

  /**
  * booleans.
  */
  public static int hash( int aSeed, boolean aBoolean ) {
    System.out.println("boolean...");
    return firstTerm( aSeed ) + ( aBoolean ? 1 : 0 );
  }

  /**
  * chars.
  */
  public static int hash( int aSeed, char aChar ) {
    System.out.println("char...");
    return firstTerm( aSeed ) + (int)aChar;
  }

  /**
  * ints.
  */
  public static int hash( int aSeed , int aInt ) {
    /*
    * Implementation Note
    * Note that byte and short are handled by this method, through
    * implicit conversion.
    */
    System.out.println("int...");
    return firstTerm( aSeed ) + aInt;
  }

  /**
  * longs.
  */
  public static int hash( int aSeed , long aLong ) {
    System.out.println("long...");
    return firstTerm(aSeed)  + (int)( aLong ^ (aLong >>> 32) );
  }

  /**
  * floats.
  */
  public static int hash( int aSeed , float aFloat ) {
    return hash( aSeed, Float.floatToIntBits(aFloat) );
  }

  /**
  * doubles.
  */
  public static int hash( int aSeed , double aDouble ) {
    return hash( aSeed, Double.doubleToLongBits(aDouble) );
  }

  /**
  * <code>aObject</code> is a possibly-null object field, and possibly an array.
  *
  * If <code>aObject</code> is an array, then each element may be a primitive
  * or a possibly-null object.
  */
  public static int hash( int aSeed , Object aObject ) {
    int result = aSeed;
    if ( aObject == null) {
      result = hash(result, 0);
    }
    else if ( ! isArray(aObject) ) {
      result = hash(result, aObject.hashCode());
    }
    else {
      int length = Array.getLength(aObject);
      for ( int idx = 0; idx < length; ++idx ) {
        Object item = Array.get(aObject, idx);
        //recursive call!
        result = hash(result, item);
      }
    }
    return result;
  }


  /// PRIVATE ///
  private static final int fODD_PRIME_NUMBER = 37;

  private static int firstTerm( int aSeed ){
    return fODD_PRIME_NUMBER * aSeed;
  }

  private static boolean isArray(Object aObject){
    return aObject.getClass().isArray();
  }
} 


Here is an example of its use. When debugging statements are uncommented in HashCodeUtil, the reuse of the boolean, char, int and long versions of hash is demonstrated :


boolean...
char...
int...
long...
long...
int...
int...
int...
int...
int...
hashCode value: -608077094

import java.util.*;

public final class ApartmentBuilding {

  public ApartmentBuilding (
    boolean aIsDecrepit,
    char aRating,
    int aNumApartments,
    long aNumTenants,
    double aPowerUsage,
    float aWaterUsage,
    byte aNumFloors,
    String aName,
    List aOptions,
    Date[] aMaintenanceChecks
  ){
    fIsDecrepit = aIsDecrepit;
    fRating = aRating;
    fNumApartments = aNumApartments;
    fNumTenants = aNumTenants;
    fPowerUsage = aPowerUsage;
    fWaterUsage = aWaterUsage;
    fNumFloors = aNumFloors;
    fName = aName;
    fOptions = aOptions;
    fMaintenanceChecks = aMaintenanceChecks;
  }

  @Override public boolean equals(Object that) {
    if ( this == that ) return true;
    if ( !(that instanceof ApartmentBuilding) ) return false;
    ApartmentBuilding thatBuilding = (ApartmentBuilding)that;
    return hasEqualState(thatBuilding);
  }

  @Override public int hashCode() {
    //this style of lazy initialization is 
    //suitable only if the object is immutable
    if ( fHashCode == 0) {
      int result = HashCodeUtil.SEED;
      result = HashCodeUtil.hash( result, fIsDecrepit );
      result = HashCodeUtil.hash( result, fRating );
      result = HashCodeUtil.hash( result, fNumApartments );
      result = HashCodeUtil.hash( result, fNumTenants );
      result = HashCodeUtil.hash( result, fPowerUsage );
      result = HashCodeUtil.hash( result, fWaterUsage );
      result = HashCodeUtil.hash( result, fNumFloors );
      result = HashCodeUtil.hash( result, fName );
      result = HashCodeUtil.hash( result, fOptions );
      result = HashCodeUtil.hash( result, fMaintenanceChecks );
      fHashCode = result;
    }
    return fHashCode;
  }

  //..other methods elided

  // PRIVATE ////

  /**
  * The following fields are chosen to exercise most of the different
  * cases.
  */
  private boolean fIsDecrepit;
  private char fRating;
  private int fNumApartments;
  private long fNumTenants;
  private double fPowerUsage;
  private float fWaterUsage;
  private byte fNumFloors;
  private String fName; //possibly null, say
  private List fOptions; //never null
  private Date[] fMaintenanceChecks; //never null
  private int fHashCode;

  /**
  * Here, for two ApartmentBuildings to be equal, all fields must be equal.
  */
  private boolean hasEqualState( ApartmentBuilding that ) {
    //note the different treatment for possibly-null fields
    return
      ( this.fName==null ? that.fName==null : this.fName.equals(that.fName) ) &&
      ( this.fIsDecrepit == that.fIsDecrepit )&&
      ( this.fRating == that.fRating )&&
      ( this.fNumApartments == that.fNumApartments ) &&
      ( this.fNumTenants == that.fNumTenants ) &&
      ( this.fPowerUsage == that.fPowerUsage ) &&
      ( this.fWaterUsage ==  that.fWaterUsage ) &&
      ( this.fNumFloors == that.fNumFloors ) &&
      ( this.fOptions.equals(that.fOptions) )&&
      ( Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks) );
  }

  /**
  * Exercise hashcode.
  */
  public static void main (String [] aArguments) {
    List options = new ArrayList();
    options.add("pool");
    Date[] maintenanceDates = new Date[1];
    maintenanceDates[0] = new Date();
    byte numFloors = 8;

    ApartmentBuilding building = new ApartmentBuilding (
      false,
      'B',
      12,
      396L,
      5.2,
      6.3f,
      numFloors,
      "Palisades",
      options,
      maintenanceDates
    );

    System.out.println("hashCode value: " + building.hashCode());
  }
} 

分享到:
评论

相关推荐

    关于Java中HashCode方法的深入理解

    主要给大家介绍了关于Java中HashCode方法的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    javascript中实现兼容JAVA的hashCode算法代码分享

    在java中一个hashCode算法,...按下Ctrl键点击hashCode方法名跟进去看了下其算法,发现是很简单的几句代码,如下所示: 代码如下: public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val

    浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率。在Java的Object类中有一个方法:  public native int hashCode();...在Java中也一样,hashCode方法的主要作用是为了配合基于

    Java中hashCode和equals方法的正确使用

     hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。  使用hashCode()和equals()  hashCode()方法被用来获取给定对象的整数。这个整数被用来确定对象被...

    如何正确实现Java中的HashCode共6页.pdf.z

    如何正确实现Java中的HashCode共6页.pdf.zip

    java中hashCode方法与equals方法的用法总结

    总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复

    hash-generator-js:一个Vue.js应用程序,其中包含Java中String类的hashCode方法的javascript实现

    哈希生成器js 一个Vue.js应用程序,其中包含Java中String类的hashCode方法的javascript实现构建设置# install dependenciesnpm install# serve with hot reload at localhost:8080npm run dev# build for production...

    Java equals 方法与hashcode 方法的深入解析

    面试时经常会问起字符串比较相关的问题,比如:字符串比较时用的什么方法,内部实现如何?hashcode的作用,以及重写equal方法,为什么要重写hashcode方法?以下就为大家解答,需要的朋友可以参考下

    Java synchronized详细解读.docx

    Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。 需要明确的几个问题: synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句...

    javascript的hashCode函数实现代码小结

    网上找了好一轮,找到个比较像样而且足够短的 hashCode 实现,是从 Java 的 hashCode 中借鉴而得的。原理见 Java hashCode() ,也可以跟这里的 Java String 的源码 参照对比一下

    HashCode作用_动力节点Java学院整理

    Java集合中有两类,一类是List,一类是Set他们之间的区别就在于List集合中的元素师有序的,且可以重复,而Set集合中元素是无序不可重复的。对于List好处理,但是对于Set而言我们要如何来保证元素不重复呢?通过迭代...

    Java编程实现用hash方法切割文件

    主要介绍了Java编程实现用hash方法切割文件,简单介绍了hash的概念,然后分享了使用方法示例,具有一定借鉴价值,需要的朋友可以了解下。

    set接口经常用的hashCode和equals方法详解

    本文档详细介绍了set接口为什么会用到hashCode和equals方法以及这两个方法的一些探讨 set不同的实现类用到的这两个方法也不同

    java2022面试宝典

    JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分,它是整个java实现跨平台的最核心的部分,负责运行字节码文件。 二.hashCode()与equals()之间的关系 在lawa中,每个对象都可以调用自己的hashCode)方法...

    java面试常见问题(超详细).pdf

    Java中的equals方法和hashCode方法有什么关系? Java中什么是重载【Overloading】?什么是覆盖【Overriding】?它们有什么区别? Java中什么是多态?如何实现多态? Java中什么是接口?它有什么作用? Java中什么是...

    java 集合 分析比较

    知道如何在特定的条件下选择适合的集合类/接口。 能正确地实现hashcode方法。

    AIC的Java课程1-6章

    第9章 常用类 4课时  理解Object类及其常用方法equals,hashCode和finalize等。  能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 ...

Global site tag (gtag.js) - Google Analytics