diff --git a/jdk/src/share/classes/java/util/Arrays.java b/jdk/src/share/classes/java/util/Arrays.java index eac5521cd86..55c54115389 100644 --- a/jdk/src/share/classes/java/util/Arrays.java +++ b/jdk/src/share/classes/java/util/Arrays.java @@ -3928,6 +3928,7 @@ public class Arrays { * @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,27 +3950,7 @@ public class Arrays { 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; @@ -3977,6 +3958,32 @@ public class Arrays { 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, diff --git a/jdk/src/share/classes/java/util/Objects.java b/jdk/src/share/classes/java/util/Objects.java index 638eaaa3d1b..3ef61bde98d 100644 --- a/jdk/src/share/classes/java/util/Objects.java +++ b/jdk/src/share/classes/java/util/Objects.java @@ -33,7 +33,7 @@ package java.util; * * @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 @@ public class Objects { 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 @@ public class Objects { 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.
@@ -84,6 +140,23 @@ public class Objects {
return String.valueOf(o);
}
+ /**
+ * 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.
diff --git a/jdk/test/java/util/Objects/BasicObjectsTest.java b/jdk/test/java/util/Objects/BasicObjectsTest.java
index f5c45f7e91f..7ffec347299 100644
--- a/jdk/test/java/util/Objects/BasicObjectsTest.java
+++ b/jdk/test/java/util/Objects/BasicObjectsTest.java
@@ -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 class BasicObjectsTest {
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 @@ public class BasicObjectsTest {
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 @@ public class BasicObjectsTest {
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 @@ public class BasicObjectsTest {
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"};