toString() 只用于调试吗?

10
除了与原始数据类型一起使用,它们当然也适用于程序员的视角。我看到的大多数(如果不是全部)实现仅在程序员的角度上有用。
编辑: 我知道我应该覆盖默认行为,这就是为什么我提到实现 :)。我确实理解在某些需要GUI内字符串表示的组件中覆盖它的价值。但是,在至少JDK中,我看到很多只有在需要调试对象实例时才会用到的实现。
为什么它源自Object类,因为它似乎只对GUI /调试等东西有用?是否还有其他用途我不知道?

2
将问题针对多种语言进行定位,必然会根据该语言的惯例得出不同的结果。 - Robin
13个回答

17

不,关键在于你应该覆盖默认的ToString()实现,以使其有用。 ToString()可以是将某些东西的值输出回UI的好方法。

一个简单的例子是,如果您有一个名称类(Name Class)其中包含三个字符串(First, Middle, Last),您可以有一个ToString()方法将其格式化为UI:“Last, First Middle”。

或者一个存储数学运算的类(Left=2,Right=3,Result=6和一个操作符枚举=Multiply),调用ToString()可得到“2 * 3 = 6”。

然而,通常更常见的是具有各种不同To<qualifier>String()方法,例如.NET中的DateTime类。(ToShortDateString()ToLongDateString()ToLongTimeString(),...)

编辑:至于为什么它是根据Object类显示,那只是因为ToString()对于任何事物都是一个有效的操作。

此外,字符串可以是在数据类型或数据使用者之间进行编组的好方法,因为它(实际上)保证可解析并且不需要额外的编码或注意。


非常完整的跟进。我只是在想,toString() 的 GUI 标签化东西被过度使用了。为什么不使用类似“实现接口 TextualRepresentation”之类的东西呢? - Camilo Díaz Repka
我同意这是一个有效的操作,但仅从程序员的角度来看。我的观点是,没有任何合同规定该方法应提供 GUI 友好的字符串或公开实例(字段)的特定内部,这些仅对程序员有用,在我看来。 - Camilo Díaz Repka
4
对UI设计而言通常不太友好,因为它没有考虑用户所在地区。这对于调试无关紧要,但对于最终用户来说非常重要。 - MSalters
2
对于Java,我完全不同意这个答案。至于C#,我不知道接受的惯例是什么。针对多种语言的问题会根据该语言的惯例得出不同的结果。 - Robin

16

我的个人偏好是,永远不要将toString()用于除调试之外的任何事情。 如果您想为对象生成字符串,请提供一个明确记录您意图的单独方法(例如getName()、getDescription()等)。永远不要依赖toString()的实现。

问题在于,许多开发人员将toString()视为调试级别的字符串,并且认为随意更改它(例如添加或删除字段)没有什么问题。还有一些自动化的toString()构建器使用反射从字段生成toString()。

我发现这种偏好多年来一直为我服务良好。


鉴于字符串是编程中最有用的构造之一,了解程序空间中的每个对象都满足提供自身字符串表示的契约可以极大地增强其功能。像任何强大的工具一样,它可能会被滥用,但避免使用它是一种浪费。 - Rex M
2
但是考虑到该合同a)未对字符串格式做出任何保证,b)未提供将字符串转换回对象的对称API,我发现这是一个非常薄弱的合同。我已经调试了许多与假设不存在的“toString”合同有关的问题。 - Alex Miller
我完全同意这个观点。我认为GUI标签-文本表示的方法被过度使用了。 - Camilo Díaz Repka
1
@Alex Miller - 完全同意。字符串表示仅意味着它应该是人类可读的,对于任何复杂对象,不要期望有漂亮的格式,只需用于调试功能。 - Robin

13

toString()方法在需要获取对象的字符串表示时非常有用。它通常用于调试,但也可以用于向用户输出操作结果。

例如,假设您有一个处理复数的Complex类。如果您想以3 + 2i这样的格式将它们打印给用户,那么定义toString()会很方便,因为您不必每次都编写格式,而且输出结果将是一致的。如果您想要更改该表示方式,例如更改为3 + 2j,则只需修改Complex类中的toString()方法即可。

因此,toString()并不仅限于调试目的,而且还是获得对象一致字符串表示的好方法。


确实如此,但是并没有任何保证能够得到“一致的字符串表示”。 - Camilo Díaz Repka
我有一个名为FooFile的类,其中包含FooFileSections。为了写入文件,我重写了文件本身的ToString()方法:FooFile.ToString(),以及每个文件部分的ToString()方法:FooFileSections.ToString()。然后,通过按正确顺序调用FooFileSections的ToString()方法来构建文件内容,最后将文本流输出。总体而言可能不是一个好的方法,但很快速和简单。 - Stein Åsmul
将操作的输出结果返回给用户。由于toString()文本未国际化,因此这个文本对用户是否有用还是值得怀疑的。 - Raedwald

7
我只能说当我改变我的类的toString方法以显示一些额外的调试信息时,我的代码会出错。
相关的代码是一个GUI库,它决定将toString的值用作某个内部内容(那是几年前的事情...我忘记具体是什么了)。最终结果是我不再使用那个库了。
我认为由于很多人把toString视为调试工具(无论你认为它应该用于什么),所以使用从中返回的值来做任何程序化的事情(如解析它)或将其显示给用户是有问题的。
如果你完全控制toString方法,那么尽管随意操作。
回答这个问题,不仅仅是用于调试,你可以按照自己的意愿使用toString。然而,如果toString发生了让你不满意的变化,请不要感到惊讶。

2
我只能说,除了调试之外,这是一个非常非常泄漏的抽象 :) - Camilo Díaz Repka

4
根据我的经验,toString()方法在除了调试和日志记录之外几乎没有什么用处。您不能依赖它的格式或内容长期存在,因此除了人类可读性之外,不要依赖它来处理任何比最简单的对象(如原始对象类型)更复杂的事情。如果有多个数据成员,请预期它们可能随着时间的推移而更改类型或数量,并且toString()方法的输出也会随之更改。
我还想强烈指出另一点,请不要在toString()方法中调用其他方法。最糟糕的是,在调试器中断点检查变量内容时,由于toString()方法中的方法调用,导致更多代码执行。

3
我认为需要指出的是,提到小写字母“t”的“toString”一词通常是在谈论Java的人,而提到大写字母“T”的“ToString”一词通常是在讨论C#的人。当然,并不是所有回答都适用这个规律。
根据我的观察(我每天都使用两种语言),C#中的程序员被鼓励重写“ToString”方法以显示有用的文本表示,而在Java中,我几乎没见过这种情况。事实上,我很少看到这种情况。
-JP

2
首先,toString 方法应返回对象的可读文本表示。

这个问题在Effective Java中被提到,作为条款10:总是重写 toString

它引用了 Java API SpecificationObject.toString 方法:

结果应该是简洁但信息丰富的表示形式,易于人类阅读。

除了调试之外,覆盖类的toString方法在将对象添加到JListJTable中时也很有用,这些默认情况下会使用toString方法在列表或表格中以文本形式显示对象。
例如,在我的情况下,我已经覆盖了添加到JList中的对象的toString方法,这样用户就可以通过GUI在列表中看到有关该项的信息。
因此,确实存在除调试之外的情况下toString方法是有用的。关键是使toString方法返回对人有用的信息,而不是使用对象的内存位置作为其文本表示的默认Object.toString实现。

1

适用于

  1. Gui(当您使用PropertyGrid,表单标题文本时的复杂属性)
  2. DataBinding(这是它运作的方式)

以及任何其他字符串输出。


0
在AS3中,我需要将一个二维数组转换成为一个一维数组。最快(运行速度)和最简单(编码时间)的解决方案是:
var new1DArray:Array = the2DArray.toString().split(",");

你可能会感到惊讶,但它实际上正在按预期工作,并且速度相当快!


0

除了其他人已经说过的,重写ToString()在使用调用它的控件时也非常有用。例如,ComboBox:

myComboBox.Items.Add(new MyClass());
// now, whatever ToString() returns is shown in the
// ComboBox, but you can get the object back by through
// the SlectedItem property.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接