默认 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 格式toString 为什么有时不靠谱IntelliJ / Eclipse 生成的代码默认用 StringBuilder 拼接,看似高效,但存在两个隐患:
null 时直接拼入 null 字符串,运行时没问题,但日志里出现 name=null 容易和真实值为字符串 "null" 混淆toString(比如嵌套的自定义对象),而该对象没重写 toString,输出仍是 @xxx,调试时依然抓瞎password、token),可能造成日志泄露toString 长什么样一个用于调试的 toString 应满足:可读、可定位、不泄露、不抛异常。建议按以下原则组织:
Collection.size() 替代全量打印,例如 tagsSize=3
,而非原值或 null
[User] name=alice, age=28, tagsSize=2
复杂对象调试时,别只靠 toString——它只是第一层快照。真正难查的问题,往往藏在字段引用的对象内部,而那个对象可能根本没重写 toString。