Fix java.util.Random's constructors.
Subclasses rely on having their overridden setSeed called by Random's
constructors, and the RI actually documents this behavior. (The
documentation even changed between Java 5 and Java 6 to make it _more_
explicit.)
This patch keeps that part of I6239d93bb46876ef1c4a5e155a6dc1ac6fab4eae
that improved our randomness, but reverts the attempt to fix Random's
uncouth behavior.
Also a regression test so we don't try to fix Random again in future.
Bug: 2502231
Change-Id: Ieea1009145c74eac9475c0cd5066dabad20eb114
diff --git a/luni/src/main/java/java/util/Random.java b/luni/src/main/java/java/util/Random.java
index f893020..d6fe0f6 100644
--- a/luni/src/main/java/java/util/Random.java
+++ b/luni/src/main/java/java/util/Random.java
@@ -52,7 +52,6 @@
*/
private double nextNextGaussian;
- // BEGIN android-changed
/**
* Constructs a random generator with an initial state that is
* unlikely to be duplicated by a subsequent instantiation.
@@ -64,14 +63,12 @@
*/
public Random() {
// Note: Using identityHashCode() to be hermetic wrt subclasses.
- internalSetSeed(
- System.currentTimeMillis() + System.identityHashCode(this));
+ setSeed(System.currentTimeMillis() + System.identityHashCode(this));
}
- // END android-changed
/**
* Construct a random generator with the given {@code seed} as the
- * initial state.
+ * initial state. Equivalent to {@code Random r = new Random(); r.setSeed(seed);}.
*
* @param seed
* the seed that will determine the initial state of this random
@@ -79,9 +76,7 @@
* @see #setSeed
*/
public Random(long seed) {
- // BEGIN android-changed
- internalSetSeed(seed);
- // END android-changed
+ setSeed(seed);
}
/**
@@ -245,7 +240,6 @@
return ((long) next(32) << 32) + next(32);
}
- // BEGIN android-changed
/**
* Modifies the seed a using linear congruential formula presented in <i>The
* Art of Computer Programming, Volume 2</i>, Section 3.2.1.
@@ -257,20 +251,7 @@
* @see #Random(long)
*/
public synchronized void setSeed(long seed) {
- internalSetSeed(seed);
- }
-
- /**
- * Sets the seed. This is used both in the constructor and in the
- * default implementation of {@link #setSeed}.
- *
- * @param seed
- * the seed that alters the state of the random number
- * generator.
- */
- private void internalSetSeed(long seed) {
this.seed = (seed ^ multiplier) & ((1L << 48) - 1);
haveNextNextGaussian = false;
}
- // END android-changed
}
diff --git a/luni/src/test/java/java/util/AllTests.java b/luni/src/test/java/java/util/AllTests.java
index 774d48b..6af29d8 100644
--- a/luni/src/test/java/java/util/AllTests.java
+++ b/luni/src/test/java/java/util/AllTests.java
@@ -25,6 +25,7 @@
suite.addTestSuite(java.util.CurrencyTest.class);
suite.addTestSuite(java.util.DateTest.class);
suite.addTestSuite(java.util.FormatterTest.class);
+ suite.addTestSuite(java.util.RandomTest.class);
suite.addTestSuite(java.util.TimeZoneTest.class);
return suite;
}
diff --git a/luni/src/test/java/java/util/RandomTest.java b/luni/src/test/java/java/util/RandomTest.java
new file mode 100644
index 0000000..e6473cb
--- /dev/null
+++ b/luni/src/test/java/java/util/RandomTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class RandomTest extends junit.framework.TestCase {
+ public void test_subclassing() throws Exception {
+ // http://b/2502231
+ // Ensure that Random's constructors call setSeed by emulating the active ingredient
+ // from the bug: the subclass' setSeed had a side-effect necessary for the correct
+ // functioning of next.
+ class MyRandom extends Random {
+ public String state;
+ public MyRandom() { super(); }
+ public MyRandom(long l) { super(l); }
+ @Override protected synchronized int next(int bits) { return state.length(); }
+ @Override public synchronized void setSeed(long seed) { state = Long.toString(seed); }
+ }
+ // Test the 0-argument constructor...
+ MyRandom r1 = new MyRandom();
+ r1.nextInt();
+ assertNotNull(r1.state);
+ // Test the 1-argument constructor...
+ MyRandom r2 = new MyRandom(123L);
+ r2.nextInt();
+ assertNotNull(r2.state);
+ }
+}