Mar*_*nix 27 java random clone random-seed
我正在为某个对象创建一个深度克隆.该对象包含一个Random.
从中检索种子是一种好习惯Random吗?如果是这样,怎么样?没有Random.getSeed().
Mad*_*nyo 11
获得种子的一种更简单的方法是生成种子并将其存储为种子.我正在使用这种方法进行游戏,并希望玩家可以选择在他希望的情况下生成完全相同的世界.所以首先我创建一个没有种子的Random对象,然后让它生成一个随机数,并在另一个随机对象中使用它作为种子.每当玩家想要关卡的种子时,我就把它存放在某个地方.默认情况下,游戏仍然是随机的.
Random rand = new Random();
//Store a random seed
long seed = rand.nextLong();
//Set the Random object seed
rand.setSeed(seed);
//do random stuff...
//Wonder what the seed is to reproduce something?
System.out.println(seed);
Run Code Online (Sandbox Code Playgroud)
小智 9
您可以做的是自己获取系统时间,然后随机播种随机数生成器并将其存储在某处或打印它以便以后使用它.
long rgenseed = System.currentTimeMillis();
Random rgen = new Random();
rgen.setSeed(rgenseed);
System.out.println("Random number generator seed is " + rgenseed);
Run Code Online (Sandbox Code Playgroud)
根据您的目的,这可能是一种很好的做法.在大多数情况下,您无需检索当前种子.例如,如果您的目的是让两个Random生成器生成相同的值序列,那么您不需要检索随机种子:您只需使用相同(预设)种子创建这两个Random对象.
Java没有提供从Random对象检索种子的标准方法.如果你真的需要这个数字,你可以解决它:序列化你的Random对象,序列化另一个Random对象(使用不同的种子),找到这两个字符串不同的8个字节,并从这8个字节中检索种子值.
以下是如何使用序列化:
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.");
}
}
Run Code Online (Sandbox Code Playgroud)
随机意图是随机的.通常,您希望两个Random生成不同的数字而不是生成相同的数字.
您可以使用序列化/反序列化复制随机数并使用反射获取"种子"字段.(但我怀疑你应该做什么)
除非序列对您至关重要,否则您可以认为Random的克隆本身或任何 new Random()
尽管有一个小怪癖,但这可以通过反射来完成:
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);
Run Code Online (Sandbox Code Playgroud)
幻数0x5DEECE66DL来自Random.java的源代码,其中为种子提供了以下内容的“初始加扰”:
private static final long multiplier = 0x5DEECE66DL;
private static final long mask = (1L << 48) - 1;
//...
private static long initialScramble(long seed) {
return (seed ^ multiplier) & mask;
}
Run Code Online (Sandbox Code Playgroud)
使用异或对其进行异或,然后将其截断为48位。因此,要重新创建种子状态,我们必须对提取的种子进行XOR。