覆盖复杂对象的 toString 方法

Overriding toString method for complex object

这是(也许)一个非常基本的问题,但我想知道是否有一些统一的最佳实践来覆盖复杂对象的 toString 方法。

假设我有一个 class 定义如下:

public class MyClass {
    private int id;
    private ClassWithLotsOfFields field1;
    private AnotherClassWithLotsOfFields field2;
    ...
    private List<ComplexObject> listOfComplexObjects;
    
    // accessors ...
}

并假设 ClassWithLotsOfFieldsAnotherClassWithLotsOfFieldsComplexObject 正在声明“复杂”类型的字段。

在这些情况下,我应该为所有这些嵌套的 class 调用 toString,创建一个“巨大的”toString 输出,还是应该以任何方式简化输出字符串?

--- 更新

例如:仅打印“嵌套”对象的某些字段是否“可接受”?或者从字符串输出中完全排除它们?

来自 Object::toString 的文档:

Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read.

强调我的。

这确实是非常主观的。没有关于如何权衡这些事情的一般规则。许多 toString() 实现 return class 名称,然后是所有字段的 toString() 结果。特定的实现可能如下所示:

class SomeClass {
    private Alpha alpha;
    private Bravo bravo;

    @Override
    public String toString() {
        return String.format("SomeClass(alpha=%s, bravo=%s)", alpha, bravo);
    }
}

甚至存在自动生成 toString() 实现的工具,例如 Lombok。

不过,上面的例子主要用于比较简单的classes。我从未见过像您描述的那样复杂的物体。如果我有一个如此复杂的对象,我会亲自包括所有内容,除了表示内部状态的字段。

但更重要的是,除非我绝对必须这样做,否则我也会避免使用您所描述的复杂对象。

如评论所示,没有严格的具体方法来决定 toString 方法的内容。但为了帮助您做出决定,请记住检查对象详细信息的三种一般情况:

  • 分钟细节,查看对象内的各种值中的任何一个。为此,您可能深入调试会话,在这种情况下,您使用的是当今 IDE 中功能强大的调试器工具。
  • 对用户的总结介绍。这通常应该设计用于需要 Locale 的本地化。为此,请注意某些 classes 如何提供 getDisplayName 方法。例如,java.time.DayOfWeek.
  • 简要地识别一个对象,用于日志记录中的消息,以及快速转储到控制台以进行测试或在开发时进行健全性检查。根据我的经验,这是 toString 的主要用途。

因此,我建议只根据需要在 toString 方法中包含足够的详细信息,以便确定地识别对象。例如,UUID 或顺序 ID 字段。还有“学号”、“员工号”、“发票号”等字段

也许包括一些额外的字段以了解数据。这几个额外的字段可能是您可能会搜索和排序的字段。

省略更多琐碎的字段,这些字段在您的大部分开发、测试和日志记录过程中可能没什么用处。

最重要的是,考虑数据的敏感性。 toString 方法往往会从很多地方被调用,而且很频繁,而且很随意。虽然其中许多调用都是短暂的,但调用 toString 进行日志记录可能会导致数据以纯文本形式写入可能存在很长时间的文件中。因此,我建议省略可能敏感、私有或具有安全隐患的字段。

请注意,在 Java 16+ 中,定义为 record 的 class 会自动获得由编译器隐式提供的默认 toString 实现。该默认实现包括您为记录指定的所有字段。对于包含许多字段或敏感字段的记录,您可以选择提供自己的 toString.

自定义实现

IDE 生成起始版本。删除不相关的字段(maxWeight、color),一些引用其他对象的字段可能会使用它们的 ID 字段。一些对象字段可能很重要,比如用于计算的 Rectangle,然后是它们的 toString。

最好是单行的,比如 ID。