UUID.randomUUID()与SecureRandom的区别

26

我想了解使用UUID.randomUUID()相比SecureRandom生成器的优势,因为前者在内部使用securerandom。


2
取决于你想做什么。 如果你需要UUID,则使用UUID.randomUUID()。 如果你需要其他形式的随机性,请直接使用SecureRandom - Andy Turner
6
将它们进行比较,好像它们是可以互换的,这有点奇怪。它们执行两种不同的功能。SecureRandom 是一个随机数生成器。UUID.randomUUID() 生成一个 UUID,这不仅仅是一个随机数。 - Jesper
3
是的,但这有什么关系呢?它们仍然是两种具有不同目的的类别,你使用哪一个取决于你需要做什么。 - Jesper
3
UUID并不完全保证唯一性,但你可以放心地假定UUID是几乎唯一的(发生冲突的概率非常小,因此你不需要担心)。 - Jesper
1
如果您想了解碰撞的概率是多少,请参阅随机UUID重复的概率 - Jesper
显示剩余6条评论
4个回答

48

好的,源代码 显示UUID.randomUUID使用SecureRandom

public static UUID  [More ...] randomUUID() {
    SecureRandom ng = numberGenerator;
    if (ng == null) {
        numberGenerator = ng = new SecureRandom();
    }
    byte[] randomBytes = new byte[16];
    ng.nextBytes(randomBytes);
    randomBytes[6]  &= 0x0f;  /* clear version        */
    randomBytes[6]  |= 0x40;  /* set to version 4     */
    randomBytes[8]  &= 0x3f;  /* clear variant        */
    randomBytes[8]  |= 0x80;  /* set to IETF variant  */
    return new UUID(randomBytes);
}

正如您所看到的,您可以使用任何一个UUID版本,但在安全UUID中,您有6个非随机位,如果您很挑剔,这可能被认为是一个劣势。


2
是的,如果我想生成唯一的ID,我可以使用SecureRandom本身来实现,对吗?这样做是否与获取类型4 UUID一样好呢?但也许我可以生成填充随机位数比122更多的唯一ID。这正确吗? - User3518958
4
可以这样做。但是,如果你希望将其用作UUID,则建议使用randomUUID。这6位在UUID规范中,保持符合规范很好:https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 - uoyilmaz
1
好的,或者说,我想我应该看一下私有构造函数UUID(randomBytes)到底是做什么的。 - User3518958
2
私有构造函数UUID(byte[] arr)不对随机生成的字节数组执行任何操作,以更改其值! - User3518958
1
@uoyilmaz,你能引用源代码摘录并附上链接吗? - Basil Bourque

15

随机数有被重复生成的随机机会。如果随机性较低(除非存在某种协调),则生成相同数字的概率就越大。

https://en.wikipedia.org/wiki/Birthday_problem
随着生成更多的随机数,出现相同数字的概率也会增加,因为每个 ID 都必须与其他所有 ID 不同。

SecureRandom 允许您选择需要多少位的随机性。如果太小,则有很大的可能性会出现重复。您可以在短短几秒钟内获得重复的 32 位随机 ID。

UUID 在 128 位(或如 uoyilmaz 指出的,122 位是随机的)上设置标准。这已经足够满足大多数使用情况。但是,如果您想要一个随机字符串,我会建议使用更多位和/或更高的进制,例如 Java 支持 36 和 64 进制,这意味着您可以拥有更短的 ID 或者相同长度的 ID 可以拥有更多的随机性。

注意:UUID 格式中有多个 - ,虽然我不清楚它们的价值,但它们只会使字符串变长。


4
翻译:破折号只是为了方便人类阅读;如果你不明白它们的用途,那么你可能是一个赛博格人 :P - Maarten Bodewes
1
@MaartenBodewes ;) “-” 似乎被放置在某些有意义的分组中,但我不知道它是什么。 - Peter Lawrey
2
破折号使人类读者更容易在布局中识别记录。https://en.wikipedia.org/wiki/Universally_unique_identifier - troyfolger
1
在规范表示中使用十六进制实际上比连字符更浪费(例如,base62表示为22个字符)。在这一点上和连字符之间,令人遗憾的是,在传输或存储中将UUID序列化为此格式的字符串非常普遍。 - Adrian Baker
1
@Adrianbaker 我更喜欢使用分布式高分辨率时间戳,并嵌入配置的 hostId。这样更易于阅读,只有 64 位,速度也更快。http://blog.vanillajava.blog/2022/01/distributed-unique-time-stamp.html - Peter Lawrey

1
感谢提供的所有技术答案。我自己也被这两者之间的区别所困惑,这也导致了我来到这里。但是,我有一个想法:如果您只调用函数一次,则没有区别,因为两种方法都生成无法预先计算的数字。但是,如果多次调用函数,则它们在这里不同,因为统计正态分布是随机数生成器的属性,而这不是UUID的属性。 UUID力求唯一性,并且实际上它使用计算机的MAC硬件地址、当前时代秒等推导出所提供的数字。最终,如果您循环调用UUID值,它将不会具有统计正态分布。

-4
UUID不是一个随机数:它是一个全局唯一标识符。你可以确信没有人能够生成相同的十六进制字符串。
而随机数则是另外一回事:它不是一个十六进制字符串,也不是全局唯一的。 这个库提供了一个更高效和完整的UUID生成器。

13
“你可以确信没有人能够生成相同的十六进制字符串。” - 这可能会让人误解:你确实可以生成相同的UUID,但是如果你遵循规则,这种情况发生的可能性非常小。 - Thomas
2
你理论上可能会遇到碰撞,但概率非常低:https://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates - uoyilmaz
1
如果你想要一个真正的通用唯一标识符,而且该值的保密性并不重要(因为它很容易预测),那么类型为1的UUID肯定是唯一的,相关的Java类可以提供这个。 - sandromark78
1
@Sandro - java.util.UUID不会生成类型1的UUID。从它生成UUID的唯一方法是要么自己提供原始数据,要么使用randomUUID生成类型4的UUID。 - Jules
1
每个伪随机字符串可以生成多次,因为数字或字母的数量是有限的。 - stinger
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接