我正在一个基于 java 的系统中工作,我需要为视觉显示中的某些元素设置 id。一类元素是字符串,所以我决定使用 String.hashCode() 方法来获取这些元素的唯一标识符。
然而,我遇到的问题是,如果 id 为负并且String.hashCode
经常返回负值,我正在使用的系统就会陷入困境。一个快速的解决方案是在哈希代码调用周围使用 Math.abs() 来保证积极的结果。我对这种方法想知道的是两个不同元素具有相同哈希代码的可能性有多大?
例如,如果一个字符串返回哈希代码 -10,另一个字符串返回哈希代码 10,则会发生错误。在我的系统中,我们谈论的是通常不超过 30 个元素大小的对象集合,所以我认为这不会真的是一个问题,但我很好奇数学说了什么。
哈希码可以被认为是伪随机数。从统计学上讲,当人口大小约为 50K(任何int
为77K)时,使用正int
哈希代码,任何两个元素之间发生碰撞的几率达到 50%。有关各种哈希代码大小的冲突概率,请参阅生日问题概率表。
此外,您单独使用Math.abs()
的想法是有缺陷的:它并不总是返回正数!在 2 的恭维算术中,Integer.MIN_VALUE
的绝对值就是它自己! 众所周知,"polygenelubricants"
的哈希代码就是这个值。
哈希不是唯一的,因此它们不是uniqueId的专有名称。
至于哈希碰撞的概率,你可以阅读生日悖论。实际上(据我回忆)当从 N 个值的均匀分布中绘制时,您应该在绘制 $\sqrt(N)$ 后预期冲突(您可能会更早发生冲突)。问题在于 Java 的hashCode
实现(尤其是在散列短字符串时)不提供均匀分布,因此您会更早地发生冲突。
您已经可以获得具有相同哈希代码的两个字符串。如果您认为您有无限数量的字符串并且只有 2^32 个可能的哈希码,这应该是显而易见的。
你只是在取绝对值时让它更有可能一点。风险很小,但如果您需要唯一 ID,这不是正确的方法。
当你只有 30-50 个值时,你可以做的是将你进入 HashMap 的每个字符串与一个正在运行的计数器一起注册为值:
HashMap StringMap = new HashMap<String,Integer>();
StringMap.add("Test",1);
StringMap.add("AnotherTest",2);
然后,您可以通过调用以下命令来获取您的唯一 ID:
StringMap.get("Test"); //returns 1