为什么默认的Object.toString()方法返回hashCode的十六进制表示形式?

13

我很好奇为什么Object.toString()会返回这个:

return getClass().getName() + "@" + Integer.toHexString(hashCode());

与此相反:

return getClass().getName() + "@" + hashCode();

以十六进制显示哈希码相比于十进制有什么好处?


与https://dev59.com/ul4b5IYBdhLWcg3wchJL密切相关。 - Raedwald
2个回答

13
哈希码通常以十六进制表示,因为这样更容易在短期记忆中记住它们。十六进制数比用十进制表示的同一数字更短且具有更大的字符变化量。此外,十六进制表示法还可以防止人们试图赋予这些数字某些含义,因为它们本身没有任何含义。使用哈希码的主要目的是作为对象的唯一标识符或助记符,而不是进行算术运算或估计大小。如果哈希码使用较长的字符串表示,我们的大脑就难以记住它们,而使用base64系统则会导致一些不便的单词被形成。在32位对象哈希码的假想JVM上,"Foo"对象的哈希码看起来可能是以下任意一个:[后面展示了一组哈希码的例子]
Binary:           com.acme.Foo@11000001110101010110101100100011
Decimal:          com.acme.Foo@3251989283
Hexadecimal:      com.acme.Foo@C1D56B23
Tetrasexagesimal: com.acme.Foo@31rMiZ

你更喜欢哪一个?

我肯定更喜欢六十进制,如果没有的话,我会选择十六进制。大多数人都会同意这个选择。

你可以在这里的网站上进行转换: https://www.mobilefish.com/services/big_number/big_number.php


3
相关的是,如果数字以十进制显示,人们可能更容易期望它们有“意义”。例如,“Fnord #194”听起来更像是第194个Fnord,而不是“Fnord@159C8EA5”。从记忆的角度来看,其他字母数字编码可能更短,更容易区分,但我认为Java想避免产生任何可能被视为冒犯的字母序列。 - supercat
我们仅仅是为了这个目的使用它。我需要知道(在storm中)我们拥有的5个Persist bolt中,每个bolt正在持久化多少数据。因此,在我们的日志记录中,我们使用它来对单个bolt实例进行排序。 - markthegrea

10

Object.hashCode 曾经是基于对象内存位置计算的。几乎所有的内存位置都以十六进制形式显示。

toString 的默认返回值并不太关心哈希码,而更关心一种用于调试的唯一标识对象的方式,哈希码在此方面提供了良好的服务(事实上,类名+内存地址的组合是真正独特的;而哈希码虽然不能保证是唯一的,但往往非常接近唯一)。


15
严格来说,Object.hashCode() 方法返回一个数字,对于某些JVM而言,该数字基于对象在“方法第一次调用时”的位置。尽管GC可能会重定位对象,但 hashCode 必须保持不变。 - Stephen C
4
有没有任何一个JVM会返回内存位置信息? - Raedwald
4
Object.hashCode默认返回一个内存地址”的说法在过去十年中发布的所有Sun/Oracle JVM中都是错误的,参见https://dev59.com/OmQo5IYBdhLWcg3wXuen#16105878。你是否考虑了其他JVM实现,或者你是想说hashCode以前曾经返回过内存位置? - meriton
1
@meriton 这是很好知道的。我的信息是基于文档,它暗示(显然不正确)通常使用内存地址。我应该澄清内存地址在哈希码计算中被使用,而不是成为哈希码。无论如何,我会更新答案。 - Konrad Rudolph
@Raedwald,感谢您向我指出这个问题;请参考我的先前回复和更新的答案。 - Konrad Rudolph
2
文档终于得到修复,首先他们删除了“通常”这个词,表示它“可能或可能不会在某个时间点被实现为对象内存地址的某些函数”,然后他们完全删除了地址的提及,我认为这是一个很好的决定。 - Holger

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