Hash Code Assist : Hash Code « Development Class « Java






Hash Code Assist

Hash Code Assist
//package org.streets.commons.assist; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * <p> * Assists in implementing {@link Object#hashCode()} methods. * </p> * * <p> * This class enables a good <code>hashCode</code> method to be built for any * class. It follows the rules laid out in the book <a * href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> * by Joshua Bloch. Writing a good <code>hashCode</code> method is actually * quite difficult. This class aims to simplify the process. * </p> * * <p> * All relevant fields from the object should be included in the * <code>hashCode</code> method. Derived fields may be excluded. In general, any * field used in the <code>equals</code> method must be used in the * <code>hashCode</code> method. * </p> * * <p> * To use this class write code as follows: * </p> * * <pre> * public class Person { * String name; * int age; * boolean smoker; * ... * * public int hashCode() { * // you pick a hard-coded, randomly chosen, non-zero, odd number * // ideally different for each class * return new HashCodeBuilder(17, 37). * append(name). * append(age). * append(smoker). * toHashCode(); * } * } * </pre> * * <p> * If required, the superclass <code>hashCode()</code> can be added using * {@link #appendSuper}. * </p> * * <p> * Alternatively, there is a method that uses reflection to determine the fields * to test. Because these fields are usually private, the method, * <code>reflectionHashCode</code>, uses * <code>AccessibleObject.setAccessible</code> to change the visibility of the * fields. This will fail under a security manager, unless the appropriate * permissions are set up correctly. It is also slower than testing explicitly. * </p> * * <p> * A typical invocation for this method would look like: * </p> * * <pre> * public int hashCode() { * return HashCodeBuilder.reflectionHashCode(this); * } * </pre> * * @author Stephen Colebourne * @author Gary Gregory * @author Pete Gieser * @since 1.0 * @version $Id: HashCodeBuilder.java 564070 2007-08-09 01:58:11Z bayard $ */publicclass HashCodeAssist { /** * <p> * A registry of objects used by reflection methods to detect cyclical * object references and avoid infinite loops. * </p> * * @since 2.3 */privatestatic ThreadLocal<Set<Integer>> registry = new ThreadLocal<Set<Integer>>() { protected Set<Integer> initialValue() { // The HashSet implementation is not synchronized, // which is just what we need here. returnnew HashSet<Integer>(); } }; /** * <p> * Returns <code>true</code> if the registry contains the given object. Used * by the reflection methods to avoid infinite loops. * </p> * * @param value * The object to lookup in the registry. * @return boolean <code>true</code> if the registry contains the given * object. * @since 2.3 */staticboolean isRegistered(Object value) { return registry.get().contains(toIdentityHashCodeInteger(value)); } /** * <p> * Appends the fields and values defined by the given object of the given * <code>Class</code>. * </p> * * @param object * the object to append details of * @param clazz * the class to append details of * @param builder * the builder to append to * @param useTransients * whether to use transient fields * @param excludeFields * Collection of String field names to exclude from use in * calculation of hash code */privatestaticvoid reflectionAppend(Object object, Class<?> clazz, HashCodeAssist builder, boolean useTransients, String... excludeFields) { if (isRegistered(object)) { return; } try { register(object); Field[] fields = clazz.getDeclaredFields(); List<String> excludedFieldList = excludeFields != null ? Arrays .asList(excludeFields) : Collections.EMPTY_LIST; AccessibleObject.setAccessible(fields, true); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if (!excludedFieldList.contains(field.getName()) && (field.getName().indexOf('$') == -1) && (useTransients || !Modifier.isTransient(field .getModifiers())) && (!Modifier.isStatic(field.getModifiers()))) { try { Object fieldValue = field.get(object); builder.append(fieldValue); } catch (IllegalAccessException e) { // this can't happen. Would get a Security exception // instead // throw a runtime exception in case the impossible // happens. thrownew InternalError( "Unexpected IllegalAccessException"); } } } } finally { unregister(object); } } /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <p> * Transient members will be not be used, as they are likely derived fields, * and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be tested. Superclass fields will be included. * </p> * * <p> * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally * these should be different for each class, however this is not vital. * Prime numbers are preferred, especially for the multiplier. * </p> * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a <code>hashCode</code> for * @return int hash code * @throws IllegalArgumentException * if the Object is <code>null</code> * @throws IllegalArgumentException * if the number is zero or even */publicstaticint reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) { return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null); } /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <p> * If the TestTransients parameter is set to <code>true</code>, transient * members will be tested, otherwise they are ignored, as they are likely * derived fields, and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be tested. Superclass fields will be included. * </p> * * <p> * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally * these should be different for each class, however this is not vital. * Prime numbers are preferred, especially for the multiplier. * </p> * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a <code>hashCode</code> for * @param testTransients * whether to include transient fields * @return int hash code * @throws IllegalArgumentException * if the Object is <code>null</code> * @throws IllegalArgumentException * if the number is zero or even */publicstaticint reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, boolean testTransients) { return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null); } /** * Calls * {@link #reflectionHashCode(int, int, Object, boolean, Class, String[])} * with excludeFields set to <code>null</code>. * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a <code>hashCode</code> for * @param testTransients * whether to include transient fields * @param reflectUpToClass * the superclass to reflect up to (inclusive), may be * <code>null</code> * @return int hash code */publicstaticint reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, boolean testTransients, Class<?> reflectUpToClass) { return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, reflectUpToClass); } /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <p> * If the TestTransients parameter is set to <code>true</code>, transient * members will be tested, otherwise they are ignored, as they are likely * derived fields, and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be included. Superclass fields will be included up * to and including the specified superclass. A null superclass is treated * as java.lang.Object. * </p> * * <p> * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally * these should be different for each class, however this is not vital. * Prime numbers are preferred, especially for the multiplier. * </p> * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @param object * the Object to create a <code>hashCode</code> for * @param testTransients * whether to include transient fields * @param reflectUpToClass * the superclass to reflect up to (inclusive), may be * <code>null</code> * @param excludeFields * array of field names to exclude from use in calculation of * hash code * @return int hash code * @throws IllegalArgumentException * if the Object is <code>null</code> * @throws IllegalArgumentException * if the number is zero or even * @since 2.0 */publicstaticint reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, boolean testTransients, Class<?> reflectUpToClass, String... excludeFields) { if (object == null) { thrownew IllegalArgumentException( "The object to build a hash code for must not be null"); } HashCodeAssist builder = new HashCodeAssist(initialNonZeroOddNumber, multiplierNonZeroOddNumber); Class<?> clazz = object.getClass(); reflectionAppend(object, clazz, builder, testTransients, excludeFields); while (clazz.getSuperclass() != null && clazz != reflectUpToClass) { clazz = clazz.getSuperclass(); reflectionAppend(object, clazz, builder, testTransients, excludeFields); } return builder.toHashCode(); } /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * This constructor uses two hard coded choices for the constants needed to * build a hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <p> * Transient members will be not be used, as they are likely derived fields, * and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be tested. Superclass fields will be included. * </p> * * @param object * the Object to create a <code>hashCode</code> for * @return int hash code * @throws IllegalArgumentException * if the object is <code>null</code> */publicstaticint reflectionHashCode(Object object) { return reflectionHashCode(17, 37, object, false, null); } /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * This constructor uses two hard coded choices for the constants needed to * build a hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <P> * If the TestTransients parameter is set to <code>true</code>, transient * members will be tested, otherwise they are ignored, as they are likely * derived fields, and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be tested. Superclass fields will be included. * </p> * * @param object * the Object to create a <code>hashCode</code> for * @param testTransients * whether to include transient fields * @return int hash code * @throws IllegalArgumentException * if the object is <code>null</code> */publicstaticint reflectionHashCode(Object object, boolean testTransients) { return reflectionHashCode(17, 37, object, testTransients, null); } // ------------------------------------------------------------------------- /** * <p> * This method uses reflection to build a valid hash code. * </p> * * <p> * This constructor uses two hard coded choices for the constants needed to * build a hash code. * </p> * * <p> * It uses <code>AccessibleObject.setAccessible</code> to gain access to * private fields. This means that it will throw a security exception if run * under a security manager, if the permissions are not set up correctly. It * is also not as efficient as testing explicitly. * </p> * * <p> * Transient members will be not be used, as they are likely derived fields, * and not part of the value of the <code>Object</code>. * </p> * * <p> * Static fields will not be tested. Superclass fields will be included. * </p> * * @param object * the Object to create a <code>hashCode</code> for * @param excludeFields * array of field names to exclude from use in calculation of * hash code * @return int hash code * @throws IllegalArgumentException * if the object is <code>null</code> */publicstaticint reflectionHashCode(Object object, String... excludeFields) { return reflectionHashCode(17, 37, object, false, null, excludeFields); } /** * <p> * Registers the given object. Used by the reflection methods to avoid * infinite loops. * </p> * * @param value * The object to register. */staticvoid register(Object value) { registry.get().add(toIdentityHashCodeInteger(value)); } /** * Returns an Integer for the given object's default hash code. * * @see System#identityHashCode(Object) * @param value * object for which the hashCode is to be calculated * @return Default int hash code */privatestaticInteger toIdentityHashCodeInteger(Object value) { returnnewInteger(System.identityHashCode(value)); } /** * <p> * Unregisters the given object. * </p> * * <p> * Used by the reflection methods to avoid infinite loops. * * @param value * The object to unregister. * @since 2.3 */staticvoid unregister(Object value) { registry.get().remove(toIdentityHashCodeInteger(value)); } /** * Constant to use in building the hashCode. */privatefinalint iConstant; /** * Running total of the hashCode. */privateint iTotal = 0; /** * <p> * Uses two hard coded choices for the constants needed to build a * <code>hashCode</code>. * </p> */public HashCodeAssist() { iConstant = 37; iTotal = 17; } /** * <p> * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally * these should be different for each class, however this is not vital. * </p> * * <p> * Prime numbers are preferred, especially for the multiplier. * </p> * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value * @param multiplierNonZeroOddNumber * a non-zero, odd number used as the multiplier * @throws IllegalArgumentException * if the number is zero or even */public HashCodeAssist(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) { if (initialNonZeroOddNumber == 0) { thrownew IllegalArgumentException( "HashCodeBuilder requires a non zero initial value"); } if (initialNonZeroOddNumber % 2 == 0) { thrownew IllegalArgumentException( "HashCodeBuilder requires an odd initial value"); } if (multiplierNonZeroOddNumber == 0) { thrownew IllegalArgumentException( "HashCodeBuilder requires a non zero multiplier"); } if (multiplierNonZeroOddNumber % 2 == 0) { thrownew IllegalArgumentException( "HashCodeBuilder requires an odd multiplier"); } iConstant = multiplierNonZeroOddNumber; iTotal = initialNonZeroOddNumber; } /** * <p> * Append a <code>hashCode</code> for a <code>boolean</code>. * </p> * <p> * This adds <code>iConstant * 1</code> to the <code>hashCode</code> and not * a <code>1231</code> or <code>1237</code> as done in java.lang.Boolean. * This is in accordance with the <quote>Effective Java</quote> design. * </p> * * @param value * the boolean to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(boolean value) { iTotal = iTotal * iConstant + (value ? 0 : 1); returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>boolean</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(boolean[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } // ------------------------------------------------------------------------- /** * <p> * Append a <code>hashCode</code> for a <code>byte</code>. * </p> * * @param value * the byte to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(byte value) { iTotal = iTotal * iConstant + value; returnthis; } // ------------------------------------------------------------------------- /** * <p> * Append a <code>hashCode</code> for a <code>byte</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(byte[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>char</code>. * </p> * * @param value * the char to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(char value) { iTotal = iTotal * iConstant + value; returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>char</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(char[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>double</code>. * </p> * * @param value * the double to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(double value) { return append(Double.doubleToLongBits(value)); } /** * <p> * Append a <code>hashCode</code> for a <code>double</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(double[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>float</code>. * </p> * * @param value * the float to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(float value) { iTotal = iTotal * iConstant + Float.floatToIntBits(value); returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>float</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(float[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for an <code>int</code>. * </p> * * @param value * the int to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(int value) { iTotal = iTotal * iConstant + value; returnthis; } /** * <p> * Append a <code>hashCode</code> for an <code>int</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(int[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>long</code>. * </p> * <p> * * @param value * the long to add to the <code>hashCode</code> * @return this */// NOTE: This method uses >> and not >>> as Effective Java and // Long.hashCode do. Ideally we should switch to >>> at // some stage. There are backwards compat issues, so // that will have to wait for the time being. cf LANG-342. public HashCodeAssist append(long value) { iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32))); returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>long</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(long[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for an <code>Object</code>. * </p> * * @param object * the Object to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(Object object) { if (object == null) { iTotal = iTotal * iConstant; } else { // 'Switch' on type of array, to dispatch to the correct handler // This handles multi dimensional arrays if (object instanceoflong[]) { append((long[]) object); } elseif (object instanceofint[]) { append((int[]) object); } elseif (object instanceofshort[]) { append((short[]) object); } elseif (object instanceofchar[]) { append((char[]) object); } elseif (object instanceofbyte[]) { append((byte[]) object); } elseif (object instanceofdouble[]) { append((double[]) object); } elseif (object instanceoffloat[]) { append((float[]) object); } elseif (object instanceofboolean[]) { append((boolean[]) object); } elseif (object instanceof Object[]) { // Not an array of primitives  append((Object[]) object); } else { iTotal = iTotal * iConstant + object.hashCode(); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for an <code>Object</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(Object[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>short</code>. * </p> * * @param value * the short to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(short value) { iTotal = iTotal * iConstant + value; returnthis; } /** * <p> * Append a <code>hashCode</code> for a <code>short</code> array. * </p> * * @param array * the array to add to the <code>hashCode</code> * @return this */public HashCodeAssist append(short[] array) { if (array == null) { iTotal = iTotal * iConstant; } else { for (int i = 0; i < array.length; i++) { append(array[i]); } } returnthis; } /** * <p> * Adds the result of super.hashCode() to this builder. * </p> * * @param superHashCode * the result of calling <code>super.hashCode()</code> * @return this HashCodeBuilder, used to chain calls. * @since 2.0 */public HashCodeAssist appendSuper(int superHashCode) { iTotal = iTotal * iConstant + superHashCode; returnthis; } /** * <p> * Return the computed <code>hashCode</code>. * </p> * * @return <code>hashCode</code> based on the fields appended */publicint toHashCode() { return iTotal; } } 








Related examples in the same category

1.Computing hash codes
2.A hash-code generator and a collection of static hash-code generation methods.
3.MD5 hash generator
4.Hash 32 String
5.Hash 64 String
6.MD5 hashing: Encodes a string
7.MD5 String
8.Hash Code BuilderHash Code Builder
9.HashCode generationHashCode generation
10.Get hash code for primitive data types
11.Return as hash code for the given object
12.Null Safe Hash Code
13.A very efficient java hash algorithm, based on the BuzHash algoritm
14.Easy implementation of hashCode
15.An implementation of the HMACT64 keyed hashing algorithm
16.Gets the hash code of an object returning zero when the object is null
17.Unify Hash
18.Secure Hash
19.FNV Hash
20.Jenkins Hash
21.Concurrent Cuckoo hashing using lock striping. Uses R/W locks for resizing. Exercise solution.
22.Concurrent Cuckoo hashing using lock striping.
23.encode Hex
24.Fowler/Noll/Vo hash algorhythm
25.Produces 32-bit hash for hash table lookup. (Jenkins Hash Function)
26.Key Value Hash
27.Paul Hsieh's Hash Function.
28.An extension of WeakReference that implements a sane equals and hashcode method.
29.Dual Key Hash Map
30.A hash map with int key and int values.
31.null Safe Equals and Hash
32.Generates a hash code for a given source code.
33.AtkinsonHash utility class implements the hash algorithm used by HyperCard's ask password command.
34.This is a very fast, non-cryptographic hash suitable for general hash-based lookup.
35.An advanced hash table supporting configurable garbage collection semantics of keys and values
36.Hash string
close