1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 package net.sf.classifier4J.util;
55
56 import java.lang.reflect.AccessibleObject;
57 import java.lang.reflect.Field;
58 import java.lang.reflect.Modifier;
59
60 /***
61 * <p>Assists in implementing {@link Object#hashCode()} methods.</p>
62 *
63 * <p> This class enables a good <code>hashCode</code> method to be built for any class. It
64 * follows the rules laid out in the book
65 * <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
66 * by Joshua Bloch. Writing a good <code>hashCode</code> method is actually quite
67 * difficult. This class aims to simplify the process.</p>
68 *
69 * <p>All relevant fields from the object should be included in the
70 * <code>hashCode</code> method. Derived fields may be excluded. In general, any
71 * field used in the <code>equals</code> method must be used in the <code>hashCode</code>
72 * method.</p>
73 *
74 * <p>To use this class write code as follows:</p>
75 * <pre>
76 * public class Person {
77 * String name;
78 * int age;
79 * boolean isSmoker;
80 * ...
81 *
82 * public int hashCode() {
83 * // you pick a hard-coded, randomly chosen, non-zero, odd number
84 * // ideally different for each class
85 * return new HashCodeBuilder(17, 37).
86 * append(name).
87 * append(age).
88 * append(smoker).
89 * toHashCode();
90 * }
91 * }
92 * </pre>
93 *
94 * <p>If required, the superclass <code>hashCode()</code> can be added
95 * using {@link #appendSuper}.</p>
96 *
97 * <p>Alternatively, there is a method that uses reflection to determine
98 * the fields to test. Because these fields are usually private, the method,
99 * <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code> to
100 * change the visibility of the fields. This will fail under a security manager,
101 * unless the appropriate permissions are set up correctly. It is also slower
102 * than testing explicitly.</p>
103 *
104 * <p>A typical invocation for this method would look like:</p>
105 * <pre>
106 * public int hashCode() {
107 * return HashCodeBuilder.reflectionHashCode(this);
108 * }
109 * </pre>
110 *
111 * @author Stephen Colebourne
112 * @author Gary Gregory
113 * @author Pete Gieser
114 * @since 1.0
115 * @version $Id: HashCodeBuilder.java,v 1.1 2005/02/04 05:30:28 nicklothian Exp $
116 */
117 public class HashCodeBuilder {
118
119 /***
120 * Constant to use in building the hashCode.
121 */
122 private final int iConstant;
123 /***
124 * Running total of the hashCode.
125 */
126 private int iTotal = 0;
127
128 /***
129 * <p>Constructor.</p>
130 *
131 * <p>This constructor uses two hard coded choices for the constants
132 * needed to build a <code>hashCode</code>.</p>
133 */
134 public HashCodeBuilder() {
135 super();
136 iConstant = 37;
137 iTotal = 17;
138 }
139
140 /***
141 * <p>Constructor.</p>
142 *
143 * <p>Two randomly chosen, non-zero, odd numbers must be passed in.
144 * Ideally these should be different for each class, however this is
145 * not vital.</p>
146 *
147 * <p>Prime numbers are preferred, especially for the multiplier.</p>
148 *
149 * @param initialNonZeroOddNumber a non-zero, odd number used as the initial value
150 * @param multiplierNonZeroOddNumber a non-zero, odd number used as the multiplier
151 * @throws IllegalArgumentException if the number is zero or even
152 */
153 public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
154 super();
155 if (initialNonZeroOddNumber == 0) {
156 throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
157 }
158 if (initialNonZeroOddNumber % 2 == 0) {
159 throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
160 }
161 if (multiplierNonZeroOddNumber == 0) {
162 throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
163 }
164 if (multiplierNonZeroOddNumber % 2 == 0) {
165 throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
166 }
167 iConstant = multiplierNonZeroOddNumber;
168 iTotal = initialNonZeroOddNumber;
169 }
170
171
172
173 /***
174 * <p>This method uses reflection to build a valid hash code.</p>
175 *
176 * <p>This constructor uses two hard coded choices for the constants
177 * needed to build a hash code.</p>
178 *
179 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
180 * fields. This means that it will throw a security exception if run under
181 * a security manager, if the permissions are not set up correctly. It is
182 * also not as efficient as testing explicitly.</p>
183 *
184 * <p>Transient members will be not be used, as they are likely derived
185 * fields, and not part of the value of the <code>Object</code>.</p>
186 *
187 * <p>Static fields will not be tested. Superclass fields will be included.</p>
188 *
189 * @param object the Object to create a <code>hashCode</code> for
190 * @return int hash code
191 * @throws IllegalArgumentException if the object is <code>null</code>
192 */
193 public static int reflectionHashCode(Object object) {
194 return reflectionHashCode(17, 37, object, false, null);
195 }
196
197 /***
198 * <p>This method uses reflection to build a valid hash code.</p>
199 *
200 * <p>This constructor uses two hard coded choices for the constants needed
201 * to build a hash code.</p>
202 *
203 * <p> It uses <code>AccessibleObject.setAccessible</code> to gain access to private
204 * fields. This means that it will throw a security exception if run under
205 * a security manager, if the permissions are not set up correctly. It is
206 * also not as efficient as testing explicitly.</p>
207 *
208 * <P>If the TestTransients parameter is set to <code>true</code>, transient
209 * members will be tested, otherwise they are ignored, as they are likely
210 * derived fields, and not part of the value of the <code>Object</code>.</p>
211 *
212 * <p>Static fields will not be tested. Superclass fields will be included.</p>
213 *
214 * @param object the Object to create a <code>hashCode</code> for
215 * @param testTransients whether to include transient fields
216 * @return int hash code
217 * @throws IllegalArgumentException if the object is <code>null</code>
218 */
219 public static int reflectionHashCode(Object object, boolean testTransients) {
220 return reflectionHashCode(17, 37, object, testTransients, null);
221 }
222
223 /***
224 * <p>This method uses reflection to build a valid hash code.</p>
225 *
226 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
227 * fields. This means that it will throw a security exception if run under
228 * a security manager, if the permissions are not set up correctly. It is
229 * also not as efficient as testing explicitly.</p>
230 *
231 * <p>Transient members will be not be used, as they are likely derived
232 * fields, and not part of the value of the <code>Object</code>.</p>
233 *
234 * <p>Static fields will not be tested. Superclass fields will be included.</p>
235 *
236 * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
237 * these should be different for each class, however this is not vital.
238 * Prime numbers are preferred, especially for the multiplier.</p>
239 *
240 * @param initialNonZeroOddNumber a non-zero, odd number used as the initial value
241 * @param multiplierNonZeroOddNumber a non-zero, odd number used as the multiplier
242 * @param object the Object to create a <code>hashCode</code> for
243 * @return int hash code
244 * @throws IllegalArgumentException if the Object is <code>null</code>
245 * @throws IllegalArgumentException if the number is zero or even
246 */
247 public static int reflectionHashCode(
248 int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
249 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
250 }
251
252 /***
253 * <p>This method uses reflection to build a valid hash code.</p>
254 *
255 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
256 * fields. This means that it will throw a security exception if run under
257 * a security manager, if the permissions are not set up correctly. It is also
258 * not as efficient as testing explicitly.</p>
259 *
260 * <p>If the TestTransients parameter is set to <code>true</code>, transient
261 * members will be tested, otherwise they are ignored, as they are likely
262 * derived fields, and not part of the value of the <code>Object</code>.</p>
263 *
264 * <p>Static fields will not be tested. Superclass fields will be included.</p>
265 *
266 * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
267 * these should be different for each class, however this is not vital.
268 * Prime numbers are preferred, especially for the multiplier.</p>
269 *
270 * @param initialNonZeroOddNumber a non-zero, odd number used as the initial value
271 * @param multiplierNonZeroOddNumber a non-zero, odd number used as the multiplier
272 * @param object the Object to create a <code>hashCode</code> for
273 * @param testTransients whether to include transient fields
274 * @return int hash code
275 * @throws IllegalArgumentException if the Object is <code>null</code>
276 * @throws IllegalArgumentException if the number is zero or even
277 */
278 public static int reflectionHashCode(
279 int initialNonZeroOddNumber, int multiplierNonZeroOddNumber,
280 Object object, boolean testTransients) {
281 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
282 }
283
284 /***
285 * <p>This method uses reflection to build a valid hash code.</p>
286 *
287 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
288 * fields. This means that it will throw a security exception if run under
289 * a security manager, if the permissions are not set up correctly. It is also
290 * not as efficient as testing explicitly.</p>
291 *
292 * <p>If the TestTransients parameter is set to <code>true</code>, transient
293 * members will be tested, otherwise they are ignored, as they are likely
294 * derived fields, and not part of the value of the <code>Object</code>.</p>
295 *
296 * <p>Static fields will not be included. Superclass fields will be included
297 * up to and including the specified superclass. A null superclass is treated
298 * as java.lang.Object.</p>
299 *
300 * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
301 * these should be different for each class, however this is not vital.
302 * Prime numbers are preferred, especially for the multiplier.</p>
303 *
304 * @param initialNonZeroOddNumber a non-zero, odd number used as the initial value
305 * @param multiplierNonZeroOddNumber a non-zero, odd number used as the multiplier
306 * @param object the Object to create a <code>hashCode</code> for
307 * @param testTransients whether to include transient fields
308 * @param reflectUpToClass the superclass to reflect up to (inclusive),
309 * may be <code>null</code>
310 * @return int hash code
311 * @throws IllegalArgumentException if the Object is <code>null</code>
312 * @throws IllegalArgumentException if the number is zero or even
313 * @since 2.0
314 */
315 public static int reflectionHashCode(
316 int initialNonZeroOddNumber,
317 int multiplierNonZeroOddNumber,
318 Object object,
319 boolean testTransients,
320 Class reflectUpToClass) {
321
322 if (object == null) {
323 throw new IllegalArgumentException("The object to build a hash code for must not be null");
324 }
325 HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
326 Class clazz = object.getClass();
327 reflectionAppend(object, clazz, builder, testTransients);
328 while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
329 clazz = clazz.getSuperclass();
330 reflectionAppend(object, clazz, builder, testTransients);
331 }
332 return builder.toHashCode();
333 }
334
335 /***
336 * <p>Appends the fields and values defined by the given object of the
337 * given <code>Class</code>.</p>
338 *
339 * @param object the object to append details of
340 * @param clazz the class to append details of
341 * @param builder the builder to append to
342 * @param useTransients whether to use transient fields
343 */
344 private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients) {
345 Field[] fields = clazz.getDeclaredFields();
346 AccessibleObject.setAccessible(fields, true);
347 for (int i = 0; i < fields.length; i++) {
348 Field f = fields[i];
349 if ((f.getName().indexOf('$') == -1)
350 && (useTransients || !Modifier.isTransient(f.getModifiers()))
351 && (!Modifier.isStatic(f.getModifiers()))) {
352 try {
353 builder.append(f.get(object));
354 } catch (IllegalAccessException e) {
355
356
357 throw new InternalError("Unexpected IllegalAccessException");
358 }
359 }
360 }
361 }
362
363
364
365 /***
366 * <p>Adds the result of super.hashCode() to this builder.</p>
367 *
368 * @param superHashCode the result of calling <code>super.hashCode()</code>
369 * @return this HashCodeBuilder, used to chain calls.
370 * @since 2.0
371 */
372 public HashCodeBuilder appendSuper(int superHashCode) {
373 iTotal = iTotal * iConstant + superHashCode;
374 return this;
375 }
376
377
378
379 /***
380 * <p>Append a <code>hashCode</code> for an <code>Object</code>.</p>
381 *
382 * @param object the Object to add to the <code>hashCode</code>
383 * @return this
384 */
385 public HashCodeBuilder append(Object object) {
386 if (object == null) {
387 iTotal = iTotal * iConstant;
388
389 } else {
390 if (object.getClass().isArray() == false) {
391
392 iTotal = iTotal * iConstant + object.hashCode();
393
394 } else {
395
396
397 if (object instanceof long[]) {
398 append((long[]) object);
399 } else if (object instanceof int[]) {
400 append((int[]) object);
401 } else if (object instanceof short[]) {
402 append((short[]) object);
403 } else if (object instanceof char[]) {
404 append((char[]) object);
405 } else if (object instanceof byte[]) {
406 append((byte[]) object);
407 } else if (object instanceof double[]) {
408 append((double[]) object);
409 } else if (object instanceof float[]) {
410 append((float[]) object);
411 } else if (object instanceof boolean[]) {
412 append((boolean[]) object);
413 } else {
414
415 append((Object[]) object);
416 }
417 }
418 }
419 return this;
420 }
421
422 /***
423 * <p>Append a <code>hashCode</code> for a <code>long</code>.</p>
424 *
425 * @param value the long to add to the <code>hashCode</code>
426 * @return this
427 */
428 public HashCodeBuilder append(long value) {
429 iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
430 return this;
431 }
432
433 /***
434 * <p>Append a <code>hashCode</code> for an <code>int</code>.</p>
435 *
436 * @param value the int to add to the <code>hashCode</code>
437 * @return this
438 */
439 public HashCodeBuilder append(int value) {
440 iTotal = iTotal * iConstant + value;
441 return this;
442 }
443
444 /***
445 * <p>Append a <code>hashCode</code> for a <code>short</code>.</p>
446 *
447 * @param value the short to add to the <code>hashCode</code>
448 * @return this
449 */
450 public HashCodeBuilder append(short value) {
451 iTotal = iTotal * iConstant + value;
452 return this;
453 }
454
455 /***
456 * <p>Append a <code>hashCode</code> for a <code>char</code>.</p>
457 *
458 * @param value the char to add to the <code>hashCode</code>
459 * @return this
460 */
461 public HashCodeBuilder append(char value) {
462 iTotal = iTotal * iConstant + value;
463 return this;
464 }
465
466 /***
467 * <p>Append a <code>hashCode</code> for a <code>byte</code>.</p>
468 *
469 * @param value the byte to add to the <code>hashCode</code>
470 * @return this
471 */
472 public HashCodeBuilder append(byte value) {
473 iTotal = iTotal * iConstant + value;
474 return this;
475 }
476
477 /***
478 * <p>Append a <code>hashCode</code> for a <code>double</code>.</p>
479 *
480 * @param value the double to add to the <code>hashCode</code>
481 * @return this
482 */
483 public HashCodeBuilder append(double value) {
484 return append(Double.doubleToLongBits(value));
485 }
486
487 /***
488 * <p>Append a <code>hashCode</code> for a <code>float</code>.</p>
489 *
490 * @param value the float to add to the <code>hashCode</code>
491 * @return this
492 */
493 public HashCodeBuilder append(float value) {
494 iTotal = iTotal * iConstant + Float.floatToIntBits(value);
495 return this;
496 }
497
498 /***
499 * <p>Append a <code>hashCode</code> for a <code>boolean</code>.</p>
500 *
501 * @param value the boolean to add to the <code>hashCode</code>
502 * @return this
503 */
504 public HashCodeBuilder append(boolean value) {
505 iTotal = iTotal * iConstant + (value ? 0 : 1);
506 return this;
507 }
508
509 /***
510 * <p>Append a <code>hashCode</code> for an <code>Object</code> array.</p>
511 *
512 * @param array the array to add to the <code>hashCode</code>
513 * @return this
514 */
515 public HashCodeBuilder append(Object[] array) {
516 if (array == null) {
517 iTotal = iTotal * iConstant;
518 } else {
519 for (int i = 0; i < array.length; i++) {
520 append(array[i]);
521 }
522 }
523 return this;
524 }
525
526 /***
527 * <p>Append a <code>hashCode</code> for a <code>long</code> array.</p>
528 *
529 * @param array the array to add to the <code>hashCode</code>
530 * @return this
531 */
532 public HashCodeBuilder append(long[] array) {
533 if (array == null) {
534 iTotal = iTotal * iConstant;
535 } else {
536 for (int i = 0; i < array.length; i++) {
537 append(array[i]);
538 }
539 }
540 return this;
541 }
542
543 /***
544 * <p>Append a <code>hashCode</code> for an <code>int</code> array.</p>
545 *
546 * @param array the array to add to the <code>hashCode</code>
547 * @return this
548 */
549 public HashCodeBuilder append(int[] array) {
550 if (array == null) {
551 iTotal = iTotal * iConstant;
552 } else {
553 for (int i = 0; i < array.length; i++) {
554 append(array[i]);
555 }
556 }
557 return this;
558 }
559
560 /***
561 * <p>Append a <code>hashCode</code> for a <code>short</code> array.</p>
562 *
563 * @param array the array to add to the <code>hashCode</code>
564 * @return this
565 */
566 public HashCodeBuilder append(short[] array) {
567 if (array == null) {
568 iTotal = iTotal * iConstant;
569 } else {
570 for (int i = 0; i < array.length; i++) {
571 append(array[i]);
572 }
573 }
574 return this;
575 }
576
577 /***
578 * <p>Append a <code>hashCode</code> for a <code>char</code> array.</p>
579 *
580 * @param array the array to add to the <code>hashCode</code>
581 * @return this
582 */
583 public HashCodeBuilder append(char[] array) {
584 if (array == null) {
585 iTotal = iTotal * iConstant;
586 } else {
587 for (int i = 0; i < array.length; i++) {
588 append(array[i]);
589 }
590 }
591 return this;
592 }
593
594 /***
595 * <p>Append a <code>hashCode</code> for a <code>byte</code> array.</p>
596 *
597 * @param array the array to add to the <code>hashCode</code>
598 * @return this
599 */
600 public HashCodeBuilder append(byte[] array) {
601 if (array == null) {
602 iTotal = iTotal * iConstant;
603 } else {
604 for (int i = 0; i < array.length; i++) {
605 append(array[i]);
606 }
607 }
608 return this;
609 }
610
611 /***
612 * <p>Append a <code>hashCode</code> for a <code>double</code> array.</p>
613 *
614 * @param array the array to add to the <code>hashCode</code>
615 * @return this
616 */
617 public HashCodeBuilder append(double[] array) {
618 if (array == null) {
619 iTotal = iTotal * iConstant;
620 } else {
621 for (int i = 0; i < array.length; i++) {
622 append(array[i]);
623 }
624 }
625 return this;
626 }
627
628 /***
629 * <p>Append a <code>hashCode</code> for a <code>float</code> array.</p>
630 *
631 * @param array the array to add to the <code>hashCode</code>
632 * @return this
633 */
634 public HashCodeBuilder append(float[] array) {
635 if (array == null) {
636 iTotal = iTotal * iConstant;
637 } else {
638 for (int i = 0; i < array.length; i++) {
639 append(array[i]);
640 }
641 }
642 return this;
643 }
644
645 /***
646 * <p>Append a <code>hashCode</code> for a <code>boolean</code> array.</p>
647 *
648 * @param array the array to add to the <code>hashCode</code>
649 * @return this
650 */
651 public HashCodeBuilder append(boolean[] array) {
652 if (array == null) {
653 iTotal = iTotal * iConstant;
654 } else {
655 for (int i = 0; i < array.length; i++) {
656 append(array[i]);
657 }
658 }
659 return this;
660 }
661
662 /***
663 * <p>Return the computed <code>hashCode</code>.</p>
664 *
665 * @return <code>hashCode</code> based on the fields appended
666 */
667 public int toHashCode() {
668 return iTotal;
669 }
670
671 }