文章目录

虽然java.lang.Object提供了toString方法的一个实现,但是,它返回的字符串通常并不是类的用户所期望看到的,它包含类的名字,以及一个“@”符号,接着是散列码的无符号十六进制表示,例如“phoneNumber@163b91”。toString的通用约定指出,被返回的字符串应该是一个”简洁的,且信息丰富,并且易于阅读的表达形式”。尽管“phoneNumber@163b91”算得上是简洁的和易于阅读的,但是与”(408)867-5309”比较起来,它不是信息丰富的。toString的约定进一步指出,“建议所有的子类都改写这个方法”

虽然遵守toString的约定并不像遵守equals和hashCode的约定那么重要,但是,提供一个好的toString实现,可以使一个类用起来更加愉快。当一个对象被传递给println、字符串连接操作符(+)以及Java中的assert的时候,toString方法会被自动调用。如果你提供了一个好的toString方法,那么,要产生一个有用的诊断消息会非常容易,如下:

System.out.println("Failed to connect:"+phoneNumber);

不管是否改写了toString方法,程序员都将会按这种方式来产生诊断消息,但是如果你没有改写toString方法的话,产生的消息也将难以理解。提供一个好的toString方法,不仅有益于这个类的实例,同样也有益于那些”包含了指向这些实例的引用”的对象,特别是集合对象。

在实际应用中,toString方法应该返回对象中包含的所有令人感兴趣的信息,譬如上面的电话号码例子那样,如果对象太大,或者对象中包含的状态信息难以用字符串来表达,这样做就有点不切实际。在这样的情况下,toString应该返回一个摘要信息,比如”Manhattan white pages(1487536 listings)”或者”Thread[main,5,main]”。理想情况下,字符串应该是自描述的。

在实现toString的时候,你必须要做出一个很重要的决定是,是否在文档中指定返回值的格式。对于值类,比如电话号码类、矩阵类。推荐这样做。指定格式的好处是,它可以被用做一种标准的、无二义性的、适合人阅读的对象表达形式。这种表达形式可以用输入和输出以及用在永久性的适合于人阅读的数据对象中,如XML文档。如果你指定了格式,一个好的做法同时也提供了一个相匹配的String构造函数,这样,程序员可以很容易地在对象和它的字符串表示之间来回转换。Java平台库中的许多值类都采用了这种做法,包括BigInteger、BigDecimal和绝大多数的原语类型包装类。

指定toString返回值的格式也有不足之处,如果这个类已经被广泛使用了,则一旦你指定了格式,则必须始终如一的坚持这种格式。程序猿将会编写出相应的代码来解析这种字符串表示、产生字符串表示,以及把字符串表示嵌入到永久数据中。

不管你是否决定指定格式,都应该在文档中明确表明你的意图。如果你要指定格式,则应该严格的这样去做,代码如下:

public String toString() {
return "(" + toPaddedString(areaCode, 3) + ")"
+ toPaddedString(exchange, 3) + "-"
+ toPaddedString(extension, 4);
}

private static String toPaddedString(int i, int length) {
String s = Integer.toString(i);
return ZEROS[length - s.length()] + s;
}

private static String[] ZEROS = { "", "0", "00", "000", "0000", "00000",
"000000", "0000000", "00000000" };

无论是否指定格式,为toString返回值中包含的所有信息,提供一种编程访问途径,这总是一个好的做法。例如PhoneNumber类应该包含针对areaCode、exchange和extension的访问方法。如果不这样做的话,就迫使那些需要这些信息的程序员不得不自己去解析这些字符串。降低了程序的性能,这个过程也很容易出错,会导致系统不稳定,如果格式发生了变化,还会导致系统崩溃。如果没有提供访问这些方法,即使你已经指明了字符串的格式是可以发生变化的,字符串格式也成了事实上的API。

文章目录