默认的 toString() 输出由类全限定名、@符号和哈希码十六进制表示组成,仅标识对象类型与JVM实例,不反映业务内容,故需重写以提供可读信息。

默认的 toString() 方法输出的字符串,比如 com.example.User@1a2b3c4d,其实由两部分组成:类全限定名 + @ + 哈希码的十六进制表示。它不反映对象内容,只是一种底层标识。
类全限定名(如 com.example.User)
这是对象实际所属类的完整路径,包括包名和类名。它告诉你“这个对象是哪个类造出来的”,但不是实例本身的特征。即使两个 User 对象属性值一模一样,只要它们是不同类加载器加载的,或者来自不同包下的同名类,这里的类名也会不同。
@ 符号只是分隔符
它没有任何语义或逻辑作用,纯粹是 Java 源码里写死的字符,用来把类名和哈希码区分开。你可以把它理解成一个视觉上的“冒号”或“破折号”,仅此而已。
十六进制哈希码(如 1a2b3c4d)
这部分是 hashCode() 方法返回的 int 值,用 Integer.toHexString() 转成十六进制后的结果。注意:
- 它通常(但不保证)与对象内存地址有关,JVM 实现可能不同
- 它不是唯一 ID —— 不同对象可能算出相同哈希码(哈希冲突)
- 它不随对象字段变化而自动更新;哪怕你改了 name 或 age,只要没重写 hashCode(),这个值就保持不变
- 它和
equals()配合使用才有意义,单独看只是个整数快照
为什么这样设计?
Object 的 toString() 本质是一个兜底方案:当开发者没提供业务含义时,至少能区分“是不是同一个类的两个不同实例”。它面向的是 JVM 层面的识别需求,而不是人眼可读的信息展示。所以你在日志里看到 User@7f56a1c2,只能知道这是某个 User 实例,但完全看不出它的 id 是 1001、姓名是张三——这正是必须重写 toString() 的根本原因。

















