From 6cc90236fc92255c3d2d9cd1aa5df07c923c6c85 Mon Sep 17 00:00:00 2001 From: mduigou Date: Tue, 13 Nov 2012 20:02:48 -0800 Subject: [PATCH] 7088913: Add compatible static hashCode(primitive) to primitive wrapper classes Summary: Adds static utility methods to each primitive wrapper class to allow calculation of a hashCode value from an unboxed primitive. Reviewed-by: darcy, smarks, dholmes --- src/share/classes/java/lang/Boolean.java | 15 ++++- src/share/classes/java/lang/Byte.java | 13 ++++ src/share/classes/java/lang/Character.java | 13 ++++ src/share/classes/java/lang/Double.java | 13 ++++ src/share/classes/java/lang/Float.java | 13 ++++ src/share/classes/java/lang/Integer.java | 13 ++++ src/share/classes/java/lang/Long.java | 13 ++++ src/share/classes/java/lang/Short.java | 13 ++++ test/java/lang/HashCode.java | 75 +++++++++++++++++++--- 9 files changed, 172 insertions(+), 9 deletions(-) diff --git a/src/share/classes/java/lang/Boolean.java b/src/share/classes/java/lang/Boolean.java index feb199465..2c4754c8a 100644 --- a/src/share/classes/java/lang/Boolean.java +++ b/src/share/classes/java/lang/Boolean.java @@ -196,11 +196,24 @@ public final class Boolean implements java.io.Serializable, * {@code true}; returns the integer {@code 1237} if this * object represents {@code false}. */ + @Override public int hashCode() { - return value ? 1231 : 1237; + return Boolean.hashCode(value); } /** + * Returns a hash code for a {@code boolean} value; compatible with + * {@code Boolean.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code boolean} value. + */ + public static int hashCode(boolean value) { + return value ? 1231 : 1237; + } + + /** * Returns {@code true} if and only if the argument is not * {@code null} and is a {@code Boolean} object that * represents the same {@code boolean} value as this object. diff --git a/src/share/classes/java/lang/Byte.java b/src/share/classes/java/lang/Byte.java index 799936f4a..c4dd62ecf 100644 --- a/src/share/classes/java/lang/Byte.java +++ b/src/share/classes/java/lang/Byte.java @@ -389,7 +389,20 @@ public final class Byte extends Number implements Comparable { * * @return a hash code value for this {@code Byte} */ + @Override public int hashCode() { + return Byte.hashCode(value); + } + + /** + * Returns a hash code for a {@code byte} value; compatible with + * {@code Byte.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code byte} value. + */ + public static int hashCode(byte value) { return (int)value; } diff --git a/src/share/classes/java/lang/Character.java b/src/share/classes/java/lang/Character.java index 53bb738ea..03134d06d 100644 --- a/src/share/classes/java/lang/Character.java +++ b/src/share/classes/java/lang/Character.java @@ -4588,7 +4588,20 @@ class Character implements java.io.Serializable, Comparable { * * @return a hash code value for this {@code Character} */ + @Override public int hashCode() { + return Character.hashCode(value); + } + + /** + * Returns a hash code for a {@code char} value; compatible with + * {@code Character.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code char} value. + */ + public static int hashCode(char value) { return (int)value; } diff --git a/src/share/classes/java/lang/Double.java b/src/share/classes/java/lang/Double.java index 5e1afaea7..040cca700 100644 --- a/src/share/classes/java/lang/Double.java +++ b/src/share/classes/java/lang/Double.java @@ -740,7 +740,20 @@ public final class Double extends Number implements Comparable { * * @return a {@code hash code} value for this object. */ + @Override public int hashCode() { + return Double.hashCode(value); + } + + /** + * Returns a hash code for a {@code double} value; compatible with + * {@code Double.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code double} value. + */ + public static int hashCode(double value) { long bits = doubleToLongBits(value); return (int)(bits ^ (bits >>> 32)); } diff --git a/src/share/classes/java/lang/Float.java b/src/share/classes/java/lang/Float.java index 4e7350791..1e8f6e354 100644 --- a/src/share/classes/java/lang/Float.java +++ b/src/share/classes/java/lang/Float.java @@ -648,7 +648,20 @@ public final class Float extends Number implements Comparable { * * @return a hash code value for this object. */ + @Override public int hashCode() { + return Float.hashCode(value); + } + + /** + * Returns a hash code for a {@code float} value; compatible with + * {@code Float.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code float} value. + */ + public static int hashCode(float value) { return floatToIntBits(value); } diff --git a/src/share/classes/java/lang/Integer.java b/src/share/classes/java/lang/Integer.java index 0943a3473..50627e991 100644 --- a/src/share/classes/java/lang/Integer.java +++ b/src/share/classes/java/lang/Integer.java @@ -918,7 +918,20 @@ public final class Integer extends Number implements Comparable { * primitive {@code int} value represented by this * {@code Integer} object. */ + @Override public int hashCode() { + return Integer.hashCode(value); + } + + /** + * Returns a hash code for a {@code int} value; compatible with + * {@code Integer.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code int} value. + */ + public static int hashCode(int value) { return value; } diff --git a/src/share/classes/java/lang/Long.java b/src/share/classes/java/lang/Long.java index 55f7b1a7e..9197a6d1e 100644 --- a/src/share/classes/java/lang/Long.java +++ b/src/share/classes/java/lang/Long.java @@ -1021,7 +1021,20 @@ public final class Long extends Number implements Comparable { * * @return a hash code value for this object. */ + @Override public int hashCode() { + return Long.hashCode(value); + } + + /** + * Returns a hash code for a {@code long} value; compatible with + * {@code Long.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code long} value. + */ + public static int hashCode(long value) { return (int)(value ^ (value >>> 32)); } diff --git a/src/share/classes/java/lang/Short.java b/src/share/classes/java/lang/Short.java index 2a1d8b550..f117095ab 100644 --- a/src/share/classes/java/lang/Short.java +++ b/src/share/classes/java/lang/Short.java @@ -394,7 +394,20 @@ public final class Short extends Number implements Comparable { * * @return a hash code value for this {@code Short} */ + @Override public int hashCode() { + return Short.hashCode(value); + } + + /** + * Returns a hash code for a {@code short} value; compatible with + * {@code Short.hashCode()}. + * + * @since 1.8 + * + * @return a hash code value for a {@code short} value. + */ + public static int hashCode(short value) { return (int)value; } diff --git a/test/java/lang/HashCode.java b/test/java/lang/HashCode.java index adf773090..d113cb0d0 100644 --- a/test/java/lang/HashCode.java +++ b/test/java/lang/HashCode.java @@ -23,18 +23,20 @@ /* * @test - * @bug 4245470 + * @bug 4245470 7088913 * @summary Test the primitive wrappers hashCode() */ +import java.util.Objects; import java.util.Random; public class HashCode { final Random rnd = new Random(); - void test(String args[]) throws Exception { - int[] ints = { + void testOrdinals(String args[]) throws Exception { + long[] longs = { + Long.MIN_VALUE, Integer.MIN_VALUE, Short.MIN_VALUE, Character.MIN_VALUE, @@ -44,20 +46,73 @@ public class HashCode { Character.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, + Long.MAX_VALUE, rnd.nextInt(), }; - for (int x : ints) { + for (long x : longs) { check( new Long(x).hashCode() == (int)((long)x ^ (long)x>>>32)); check(Long.valueOf(x).hashCode() == (int)((long)x ^ (long)x>>>32)); - check( new Integer(x).hashCode() == x); - check(Integer.valueOf(x).hashCode() == x); + check( (new Long(x)).hashCode() == Long.hashCode(x)); + check( new Integer((int)x).hashCode() == (int) x); + check(Integer.valueOf((int)x).hashCode() == (int) x); + check( (new Integer((int)x)).hashCode() == Integer.hashCode((int)x)); check( new Short((short)x).hashCode() == (short) x); check(Short.valueOf((short)x).hashCode() == (short) x); + check( (new Short((short)x)).hashCode() == Short.hashCode((short)x)); check( new Character((char) x).hashCode() == (char) x); check(Character.valueOf((char) x).hashCode() == (char) x); + check( (new Character((char)x)).hashCode() == Character.hashCode((char)x)); check( new Byte((byte) x).hashCode() == (byte) x); check(Byte.valueOf((byte) x).hashCode() == (byte) x); + check( (new Byte((byte)x)).hashCode() == Byte.hashCode((byte)x)); + } + } + + void testBoolean() { + check( Boolean.FALSE.hashCode() == 1237); + check( Boolean.TRUE.hashCode() == 1231); + check( Boolean.valueOf(false).hashCode() == 1237); + check( Boolean.valueOf(true).hashCode() == 1231); + check( (new Boolean(false)).hashCode() == 1237); + check( (new Boolean(true)).hashCode() == 1231); + check( Boolean.hashCode(false) == 1237); + check( Boolean.hashCode(true) == 1231); + } + + void testFloat() { + float[] floats = { + Float.NaN, + Float.NEGATIVE_INFINITY, + -1f, + 0f, + 1f, + Float.POSITIVE_INFINITY + }; + + for(float f : floats) { + check( Float.hashCode(f) == Float.floatToIntBits(f)); + check( Float.valueOf(f).hashCode() == Float.floatToIntBits(f)); + check( (new Float(f)).hashCode() == Float.floatToIntBits(f)); + } + } + + void testDouble() { + double[] doubles = { + Double.NaN, + Double.NEGATIVE_INFINITY, + -1f, + 0f, + 1f, + Double.POSITIVE_INFINITY + }; + + for(double d : doubles) { + long bits = Double.doubleToLongBits(d); + int bitsHash = (int)(bits^(bits>>>32)); + check( Double.hashCode(d) == bitsHash); + check( Double.valueOf(d).hashCode() == bitsHash); + check( (new Double(d)).hashCode() == bitsHash); } } @@ -69,12 +124,16 @@ public class HashCode { void unexpected(Throwable t) {failed++; t.printStackTrace();} void check(boolean cond) {if (cond) pass(); else fail();} void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); + if (Objects.equals(x,y)) pass(); else fail(x + " not equal to " + y);} public static void main(String[] args) throws Throwable { new HashCode().instanceMain(args);} public void instanceMain(String[] args) throws Throwable { - try {test(args);} catch (Throwable t) {unexpected(t);} + try { testOrdinals(args); + testBoolean(); + testFloat(); + testDouble(); + } catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} } -- GitLab