【问题标题】:Why does the default Object.toString() return a hex representation of the hashCode?为什么默认的 Object.toString() 返回 hashCode 的十六进制表示?
【发布时间】:2011-04-13 18:28:54
【问题描述】:

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

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

与此相反:

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

将哈希码显示为十六进制而不是十进制有什么好处?

【问题讨论】:

标签: java hash tostring hashcode


【解决方案1】:

简答:

哈希码通常以十六进制显示,因为这样我们更容易将它们保留在我们的短期记忆中,因为与以十进制表示的相同数字相比,十六进制数字更短且字符种类更多。

更长的答案:

十进制有两件事方便:

  • 做算术
  • 估计震级

但是,这些操作不适用于哈希码。您当然不会在脑海中将哈希码添加在一起,也不会关心哈希码与另一个哈希码相比有多大。

您可能对哈希码所做的事情是它们的唯一用途:判断两个哈希码是否可能引用同一个对象,或者肯定引用不同的对象。

换句话说,您将使用它们作为对象的唯一标识符或助记符。因此,哈希码是一个数字这一事实实际上是完全不相关的。你不妨把它想象成一个哈希字符串。

好吧,碰巧我们的大脑发现在短期记忆(为了比较)中保留由 16 个不同字符组成的短字符串比仅由 10 个不同字符组成的长字符串要容易得多。

为了进一步说明这个类比的荒谬性,想象一下如果哈希码用二进制表示,其中每个数字都比十进制长得多,而且字符种类要少得多。如果您现在看到哈希码 010001011011100010100100101011,然后在 10 秒后再次看到,您是否有最小的机会判断您正在查看相同的哈希码? (我不能,即使我同时看这两个数字。我必须逐个数字地比较它们。)

在另一端是四十六进制编号系统,即以 64 为基数。该系统中的数字包括:

  • 数字 0-9,加:
  • 大写字母 A-Z,加:
  • 小写字母 a-z,加:
  • 使用“+”和“/”等几个符号可以达到 64。

Tetrasexagesimal 显然比低基数系统具有更多的字符多样性,其中表达的数字非常简洁也就不足为奇了。 (我不确定为什么 JVM 不使用这个系统来处理哈希码;也许有些谨慎的人担心机会可能会导致形成某些不方便的四字母词?)

因此,在具有 32 位对象哈希码的假设 JVM 上,您的“Foo”对象的哈希码可能如下所示:

Binary:           com.acme.Foo@11000001110101010110101100100011
Decimal:          com.acme.Foo@3251989283
Hexadecimal:      com.acme.Foo@C1D56B23
Tetrasexagesimal: com.acme.Foo@31rMiZ

你更喜欢哪一个?

我肯定更喜欢 tetrasexagesimal,如果没有这个,我会满足于十六进制。大多数人都会同意。

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

【讨论】:

  • 在相关说明中,如果数字以十进制显示,人们可能更倾向于期望它们“意味着”某些东西。例如,“Fnord #194”听起来更像是 194th Fnord,而不是“Fnord@159C8EA5”。从助记符的角度来看,其他字母数字编码可能更短且更容易区分,但我认为 Java 希望避免产生任何可能被视为冒犯的字母序列。
  • 我们将其用于此目的。我需要知道(在暴风雨中)我们拥有的 5 个 Persist 螺栓中的哪个 Persist 螺栓持续了多少。因此,在我们的日志记录中,我们使用它对螺栓的单个实例进行排序。
【解决方案2】:

Object.hashCode 曾经被计算为based on a memory location where the object is located。内存位置几乎普遍显示为十六进制。

toString 的默认返回值对哈希码不是很感兴趣,而是为了调试目的唯一标识对象的方式,并且哈希码很好地用于识别目的(在事实上,类名 + 内存地址的组合确实是唯一的;虽然不能保证哈希码是唯一的,但它通常很接近)。

【讨论】:

  • 严格来说Object.hashCode(),它返回一个数字,对于某些JVM是基于对象的位置在第一次调用该方法时。 GC 可能会重新定位对象,但hashCode 必须保持不变。
  • 实际上有 any 个 JVM 会为其返回内存位置吗?
  • Object.hashCode 默认返回内存地址”的说法对于过去十年发布的所有 Sun/Oracle JVM 来说都是错误的,c.f. stackoverflow.com/questions/16105420/…。您是否考虑过其他一些 JVM 实现,或者您的意思是说 hashCode 用于返回一个内存位置?
  • @meriton 很高兴知道这一点。我的信息基于on the documentation,这意味着(显然不正确)通常使用内存地址。我应该澄清一下,内存地址在哈希码的计算中使用,而不是作为哈希码。无论如何,我会更新答案。
  • 文档终于得到修复,首先they removed the “typically” 说它“可能会或可能不会在某个时间点实现为对象内存地址的某些函数”,然后,they removed the mentioning of addresses completely,这是一个很好的决定,恕我直言。
猜你喜欢
  • 2017-03-04
  • 1970-01-01
  • 2022-01-09
  • 2011-09-12
  • 2021-08-31
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多