How do I get the seed from a Random in Java?
我正在为某个对象创建深度克隆。对象包含一个
从
你所能做的就是自己获得系统时间,然后用它来输入随机数生成器,并将其存储在某个地方或打印出来,以便以后使用。
1 2 3 4 |
获取种子的一个更简单的方法是生成一个种子并将其存储为种子。我在游戏中使用这种方法,如果玩家愿意的话,我想让他选择生成完全相同的世界。因此,首先我创建一个没有种子的随机对象,然后让它生成一个随机数,并在另一个随机对象中使用它作为种子。每当玩家想要这个关卡的种子,我就把它储存在某个地方。默认情况下,游戏仍然是随机的。
1 2 3 4 5 6 7 8 9 10 |
这可能是一个好的实践,取决于你的目的。在大多数情况下,您不需要检索当前种子。例如,如果您的目的是让两个随机生成器生成相同的值序列,那么您不需要检索随机种子:您只需使用相同(预设)种子创建这两个随机对象。
Java不提供从随机对象中检索种子的标准方法。如果您真的需要这个数字,您可以处理它:序列化您的随机对象,序列化另一个随机对象(使用不同的种子),找到这两个字符串不同的8个字节,并从这8个字节中检索种子值。
下面是如何进行序列化:
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 55 | import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.Random; public class SeedGetter { static long getSeed(Random random) { byte[] ba0, ba1, bar; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(128); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(new Random(0)); ba0 = baos.toByteArray(); baos = new ByteArrayOutputStream(128); oos = new ObjectOutputStream(baos); oos.writeObject(new Random(-1)); ba1 = baos.toByteArray(); baos = new ByteArrayOutputStream(128); oos = new ObjectOutputStream(baos); oos.writeObject(random); bar = baos.toByteArray(); } catch (IOException e) { throw new RuntimeException("IOException:" + e); } if (ba0.length != ba1.length || ba0.length != bar.length) throw new RuntimeException("bad serialized length"); int i = 0; while (i < ba0.length && ba0[i] == ba1[i]) { i++; } int j = ba0.length; while (j > 0 && ba0[j - 1] == ba1[j - 1]) { j--; } if (j - i != 6) throw new RuntimeException("6 differing bytes not found"); // The constant 0x5DEECE66DL is from // http://download.oracle.com/javase/6/docs/api/java/util/Random.html . return ((bar[i] & 255L) << 40 | (bar[i + 1] & 255L) << 32 | (bar[i + 2] & 255L) << 24 | (bar[i + 3] & 255L) << 16 | (bar[i + 4] & 255L) << 8 | (bar[i + 5] & 255L)) ^ 0x5DEECE66DL; } public static void main(String[] args) { Random random = new Random(12345); if (getSeed(random) != 12345) throw new RuntimeException("Bad1"); random.nextInt(); long seed = getSeed(random); if (seed == 12345) throw new RuntimeException("Bad2"); Random random2 = new Random(seed); if (random.nextInt() != random2.nextInt()) throw new RuntimeException("Bad3"); System.out.println("getSeed OK."); } } |
随机的目的是随机的。通常,您希望两个随机数产生不同的数字,而不是产生相同的数字。
您可以使用串行化/取消串行化来复制随机数据,并使用反射来获取"seed"字段。(但我怀疑你也应该这样做)
除非序列对您至关重要,否则您可以认为随机数的克隆是其自身或任何
这可以通过反射来实现,尽管有一个小的怪癖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Random r = ...; //this is the random you want to clone long theSeed; try { Field field = Random.class.getDeclaredField("seed"); field.setAccessible(true); AtomicLong scrambledSeed = (AtomicLong) field.get(r); //this needs to be XOR'd with 0x5DEECE66DL theSeed = scrambledSeed.get(); } catch (Exception e) { //handle exception } Random clonedRandom = new Random(theSeed ^ 0x5DEECE66DL); |
神奇的数字
1 2 3 4 5 6 | private static final long multiplier = 0x5DEECE66DL; private static final long mask = (1L << 48) - 1; //... private static long initialScramble(long seed) { return (seed ^ multiplier) & mask; } |
其中xor是随机数,并将其截断为48位。因此,为了重新创建种子状态,我们必须XOR我们提取的种子。
有趣的悖论…我不会将克隆的
我来这里的原因是我需要记住种子,以防我需要重新创建在特定程序运行中发生的事情。我使用的代码是:
1 2 | long seed = random.nextLong(); random.setSeed(seed); |
虽然这不完全是要求的,但我认为这可能是要求的。