--- old/src/share/classes/java/util/Arrays.java 2009-10-23 11:07:24.000000000 -0700 +++ new/src/share/classes/java/util/Arrays.java 2009-10-23 11:07:23.000000000 -0700 @@ -3928,6 +3928,7 @@ * @param a2 the other array to be tested for equality * @return true if the two arrays are equal * @see #equals(Object[],Object[]) + * @see Objects#deepEquals(Object, Object) * @since 1.5 */ public static boolean deepEquals(Object[] a1, Object[] a2) { @@ -3949,34 +3950,40 @@ return false; // Figure out whether the two elements are equal - boolean eq; - if (e1 instanceof Object[] && e2 instanceof Object[]) - eq = deepEquals ((Object[]) e1, (Object[]) e2); - else if (e1 instanceof byte[] && e2 instanceof byte[]) - eq = equals((byte[]) e1, (byte[]) e2); - else if (e1 instanceof short[] && e2 instanceof short[]) - eq = equals((short[]) e1, (short[]) e2); - else if (e1 instanceof int[] && e2 instanceof int[]) - eq = equals((int[]) e1, (int[]) e2); - else if (e1 instanceof long[] && e2 instanceof long[]) - eq = equals((long[]) e1, (long[]) e2); - else if (e1 instanceof char[] && e2 instanceof char[]) - eq = equals((char[]) e1, (char[]) e2); - else if (e1 instanceof float[] && e2 instanceof float[]) - eq = equals((float[]) e1, (float[]) e2); - else if (e1 instanceof double[] && e2 instanceof double[]) - eq = equals((double[]) e1, (double[]) e2); - else if (e1 instanceof boolean[] && e2 instanceof boolean[]) - eq = equals((boolean[]) e1, (boolean[]) e2); - else - eq = e1.equals(e2); - + boolean eq = deepEquals0(e1, e2); + if (!eq) return false; } return true; } + static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) + eq = deepEquals ((Object[]) e1, (Object[]) e2); + else if (e1 instanceof byte[] && e2 instanceof byte[]) + eq = equals((byte[]) e1, (byte[]) e2); + else if (e1 instanceof short[] && e2 instanceof short[]) + eq = equals((short[]) e1, (short[]) e2); + else if (e1 instanceof int[] && e2 instanceof int[]) + eq = equals((int[]) e1, (int[]) e2); + else if (e1 instanceof long[] && e2 instanceof long[]) + eq = equals((long[]) e1, (long[]) e2); + else if (e1 instanceof char[] && e2 instanceof char[]) + eq = equals((char[]) e1, (char[]) e2); + else if (e1 instanceof float[] && e2 instanceof float[]) + eq = equals((float[]) e1, (float[]) e2); + else if (e1 instanceof double[] && e2 instanceof double[]) + eq = equals((double[]) e1, (double[]) e2); + else if (e1 instanceof boolean[] && e2 instanceof boolean[]) + eq = equals((boolean[]) e1, (boolean[]) e2); + else + eq = e1.equals(e2); + return eq; + } + /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, --- old/src/share/classes/java/util/Objects.java 2009-10-23 11:07:24.000000000 -0700 +++ new/src/share/classes/java/util/Objects.java 2009-10-23 11:07:24.000000000 -0700 @@ -33,7 +33,7 @@ * * @since 1.7 */ -public class Objects { +public final class Objects { private Objects() { throw new AssertionError("No java.util.Objects instances for you!"); } @@ -57,6 +57,32 @@ return (a == b) || (a != null && a.equals(b)); } + /** + * Returns {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise. + * + * Two {@code null} values are deeply equal. If both arguments are + * arrays, the algorithm in {@link Arrays#deepEquals(Object[], + * Object[]) Arrays.deepEquals} is used to determine equality. + * Otherwise, equality is determined by using the {@link + * Object#equals equals} method of the first argument. + * + * @param a an object + * @param b an object to be compared with {@code a} for deep equality + * @return {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise + * @see Arrays#deepEquals(Object[], Object[]) + * @see Objects#equals(Object, Object) + */ + public static boolean deepEquals(Object a, Object b) { + if (a == b) + return true; + else if (a == null || b == null) + return false; + else + return Arrays.deepEquals0(a, b); + } + /** * Returns the hash code of a non-{@code null} argument and 0 for * a {@code null} argument. @@ -70,6 +96,36 @@ return o != null ? o.hashCode() : 0; } + /** + * Generates a hash code for a sequence of input values. The hash + * code is generated as if all the input values were placed into an + * array, and that array were hashed by calling {@link + * Arrays#hashCode(Object[])}. + * + *

This method is useful for implementing {@link + * Object#hashCode()} on objects containing multiple fields. For + * example, if an object that has three fields, {@code x}, {@code + * y}, and {@code z}, one could write: + * + *

+    * @Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * 
+ * + * Warning: When a single object reference is supplied, the returned + * value does not equal the hash code of that object reference. This + * value can be computed by calling {@link #hashCode(Object)}. + * + * @param values the values to be hashed + * @return a hash value of the sequence of input values + * @see Arrays#hashCode + * @see List#hashCode + */ + public static int hash(Object... values) { + return Arrays.hashCode(values); + } + /** * Returns the result of calling {@code toString} for a non-{@code * null} argument and {@code "null"} for a {@code null} argument. @@ -85,6 +141,23 @@ } /** + * Returns the result of calling {@code toString} on the first + * argument if the first argument is not {@code null} and returns + * the second argument otherwise. + * + * @param o an object + * @param nullDefault string to return if the first argument is + * {@code null} + * @return the result of calling {@code toString} on the first + * argument if it is not {@code null} and the second argument + * otherwise. + * @see Objects#toString(Object) + */ + public static String toString(Object o, String nullDefault) { + return (o != null) ? o.toString() : nullDefault; + } + + /** * Returns 0 if the arguments are identical and {@code * c.compare(a, b)} otherwise. * Consequently, if both arguments are {@code null} 0 --- old/test/java/util/Objects/BasicObjectsTest.java 2009-10-23 11:07:25.000000000 -0700 +++ new/test/java/util/Objects/BasicObjectsTest.java 2009-10-23 11:07:25.000000000 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 6797535 + * @bug 6797535 6889858 6891113 * @summary Basic tests for methods in java.util.Objects * @author Joseph D. Darcy */ @@ -34,8 +34,11 @@ public static void main(String... args) { int errors = 0; errors += testEquals(); + errors += testDeepEquals(); errors += testHashCode(); + errors += testHash(); errors += testToString(); + errors += testToString2(); errors += testCompare(); errors += testNonNull(); if (errors > 0 ) @@ -60,6 +63,36 @@ return errors; } + private static int testDeepEquals() { + int errors = 0; + Object[] values = {null, + null, // Change to values later + new byte[] {(byte)1}, + new short[] {(short)1}, + new int[] {1}, + new long[] {1L}, + new char[] {(char)1}, + new float[] {1.0f}, + new double[]{1.0d}, + new String[]{"one"}}; + values[1] = values; + + for(int i = 0; i < values.length; i++) + for(int j = 0; j < values.length; j++) { + boolean expected = (i == j); + Object a = values[i]; + Object b = values[j]; + boolean result = Objects.deepEquals(a, b); + if (result != expected) { + errors++; + System.err.printf("When equating %s to %s, got %b instead of %b%n.", + a, b, result, expected); + } + } + + return errors; + } + private static int testHashCode() { int errors = 0; errors += (Objects.hashCode(null) == 0 ) ? 0 : 1; @@ -68,6 +101,19 @@ return errors; } + private static int testHash() { + int errors = 0; + + Object[] data = new String[]{"perfect", "ham", "THC"}; + + errors += ((Objects.hash((Object[])null) == 0) ? 0 : 1); + + errors += (Objects.hash("perfect", "ham", "THC") == + Arrays.hashCode(data)) ? 0 : 1; + + return errors; + } + private static int testToString() { int errors = 0; errors += ("null".equals(Objects.toString(null)) ) ? 0 : 1; @@ -76,6 +122,14 @@ return errors; } + private static int testToString2() { + int errors = 0; + String s = "not the default"; + errors += (s.equals(Objects.toString(null, s)) ) ? 0 : 1; + errors += (s.equals(Objects.toString(s, "another string")) ) ? 0 : 1; + return errors; + } + private static int testCompare() { int errors = 0; String[] values = {"e. e. cummings", "zzz"};