默认 toString 输出如 com.example.User@1b6d3586,因 Object 的 toString 返回“类名@hashCode 十六进制”,无法反映字段真实值;重写时应使用 Objects.toString() 处理 null,避免 NPE 和日志混淆,并排除敏感字段与大对象以保障可读性、安全性与调试有效性。

为什么默认的 toString 输出看起来像 com.example.User@1b6d3586
Java 中所有类都继承自 Object,其默认 toString() 返回的是 类名 + @ + hashCode 的十六进制表示。这个值对调试几乎没用——你无法从中看出对象当前字段的真实值。
重写 toString 的标准写法(含空值安全)
手动拼接字符串容易出错,尤其遇到 null 字段时抛 NullPointerException。推荐用 Objects.toString() 或 String.format(),避免显式判空。
public class User {
private String name;
private Integer age;
private List tags;
@Override
public String toString() {
return String.format("User{name=%s, age=%s, tags=%s}",
Objects.toString(name, "null"),
Objects.toString(age, "null"),
Objects.toString(tags, "[]"));
}
}
-
Objects.toString(obj, "default")是关键:第二个参数是null时的替代值 - 不用
name == null ? "null" : name手动三元判断,既啰嗦又易漏 - 避免直接调用
tags.toString()——如果tags是自定义集合且未重写toString,可能又回到@xxx格式
IDE 自动生成的 toString 为什么有时不靠谱
IntelliJ / Eclipse 生成的代码默认用 StringBuilder 拼接,看似高效,但存在两个隐患:
- 字段为
null时直接拼入null字符串,运行时没问题,但日志里出现name=null容易和真实值为字符串"null"混淆 - 若字段类型本身也依赖默认
toString(比如嵌套的自定义对象),而该对象没重写toString,输出仍是@xxx,调试时依然抓瞎 - 生成逻辑不会自动跳过敏感字段(如
password、token),可能造成日志泄露
调试时真正有用的 toString 长什么样
一个用于调试的 toString 应满足:可读、可定位、不泄露、不抛异常。建议按以下原则组织:
立即学习“Java免费学习笔记(深入)”;
- 只包含核心业务字段,排除大集合、字节数组、流等不适合打印的内容
- 对集合类统一用
Collection.size()替代全量打印,例如tagsSize=3 - 敏感字段统一显示为
,而非原值或null - 开头加类标识,方便 grep 日志:
[User] name=alice, age=28, tagsSize=2
复杂对象调试时,别只靠 toString——它只是第一层快照。真正难查的问题,往往藏在字段引用的对象内部,而那个对象可能根本没重写 toString。










