root/trunk/src/java/org/jcoderz/commons/util/HashCodeUtil.java

Revision 1011, 6.4 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.util;
34
35
36import java.lang.reflect.Array;
37
38
39/**
40 * Collected methods which allow easy implementation of
41 * <code>hashCode</code>. Example use case:
42 *
43 * <pre>
44 * public int hashCode ()
45 * {
46 *    int result = HashCodeUtil.SEED;
47 *    //collect the contributions of various fields
48 *    result = HashCodeUtil.hash(result, mPrimitive);
49 *    result = HashCodeUtil.hash(result, mObject);
50 *    result = HashCodeUtil.hash(result, mArray);
51 *    return result;
52 * }
53 * </pre>
54 *
55 * @author Michael Griffel
56 */
57public final class HashCodeUtil
58{
59   /**
60    * An initial value for a <code>hashCode</code>, to which is added
61    * contributions from fields. Using a non-zero value decreases
62    * collisons of <code>hashCode</code> values.
63    */
64   public static final int SEED = 23;
65
66   /**
67    * An factor that is used in the first term to multiply the <i>old</i>
68    * hash code value.
69    */
70   private static final int ODD_PRIME_NUMBER = 37;
71
72   /**
73    * No instances allowed.
74    */
75   private HashCodeUtil ()
76   {
77      // Utility class  -- provides only static helper methods.
78   }
79
80   /**
81    * Constructs a new seed using the given Boolean and the previous seed.
82    * @param aSeed the previous seed value.
83    * @param aBoolean the Boolean that should be added to the new seed.
84    * @return the new seed.
85    */
86   public static int hash (int aSeed, boolean aBoolean)
87   {
88      return firstTerm(aSeed) + (aBoolean ? 1 : 0);
89   }
90
91   /**
92    * Constructs a new seed using the given boolean and the previous seed.
93    * @param aSeed the previous seed value.
94    * @param aChar the character that should be added to the new seed.
95    * @return the new seed.
96    */
97   public static int hash (int aSeed, char aChar)
98   {
99      return firstTerm(aSeed) + aChar;
100   }
101
102   /**
103    * Constructs a new seed using the given integer and the previous seed.
104    * Note that byte and short are handled by this method,
105    * through implicit conversion.
106    * @param aSeed the previous seed value.
107    * @param aInt the integer that should be added to the new seed.
108    * @return the new seed.
109    */
110   public static int hash (int aSeed, int aInt)
111   {
112      return firstTerm(aSeed) + aInt;
113   }
114
115   /**
116    * Constructs a new seed using the given long and the previous seed.
117    * @param aSeed the previous seed value.
118    * @param aLong the long value that should be added to the new seed.
119    * @return the new seed.
120    */
121   public static int hash (int aSeed, long aLong)
122   {
123      return firstTerm(aSeed) + (int) (aLong
124            ^ (aLong >>> Constants.BITS_PER_INTEGER));
125   }
126
127   /**
128    * Constructs a new seed using the given float and the previous seed.
129    * @param aSeed the previous seed value.
130    * @param aFloat the float that should be added to the new seed.
131    * @return the new seed.
132    */
133   public static int hash (int aSeed, float aFloat)
134   {
135      return hash(aSeed, Float.floatToIntBits(aFloat));
136   }
137
138   /**
139    * Constructs a new seed using the given double and the previous seed.
140    * @param aSeed the previous seed value.
141    * @param aDouble the double that should be added to the new seed.
142    * @return the new seed.
143    */
144   public static int hash (int aSeed, double aDouble)
145   {
146      return hash(aSeed, Double.doubleToLongBits(aDouble));
147   }
148
149   /**
150    * Constructs a new seed using the given object and the previous seed.
151    *
152    * <code>aObject</code> is a possibly-null object field, and possibly
153    * an array. If <code>aObject</code> is an array, then each element
154    * may be a primitive or a possibly-null object.
155    *
156    * @param aSeed the previous seed value.
157    * @param aObject the integer that should be added to the new seed.
158    * @return the new seed.
159    */
160   public static int hash (int aSeed, Object aObject)
161   {
162      int result = aSeed;
163
164      if (aObject == null)
165      {
166         result = hash(result, 0);
167      }
168      else if (!isArray(aObject))
169      {
170         result = hash(result, aObject.hashCode());
171      }
172      else
173      {
174         final int length = Array.getLength(aObject);
175         for (int i = 0; i < length; ++i)
176         {
177            final Object item = Array.get(aObject, i);
178            //recursive call!
179            result = hash(result, item);
180         }
181         result = hash(result, length);
182      }
183      return result;
184   }
185
186   /**
187    * Calculates the first part (term) of the seed.
188    * @param aSeed the old seed value.
189    * @return the part of the new seed.
190    */
191   private static int firstTerm (int aSeed)
192   {
193      return ODD_PRIME_NUMBER * aSeed;
194   }
195
196   /**
197    * Returns <code>true</code> if the given object represents an array.
198    * @return <code>true</code> if the given object represents an array;
199    *       <code>false</code> otherwise.
200    */
201   private static boolean isArray (Object aObject)
202   {
203      return aObject.getClass().isArray();
204   }
205}
Note: See TracBrowser for help on using the browser.