文章作者:Tyan
博客:noahsnail.com | CSDN | 簡書
Item10: Always override toString
While java.lang.Object
provides an implementation of the toString
method, the string that it returns is generally not what the user of your class wants to see. It consists of the class name followed by an “at” sign (@) and the unsigned hexadecimal representation of the hash code, for example, “PhoneNumber@163b91.” The general contract for toString
says that the returned string should be “a concise but informative representation that is easy for a person to read” [JavaSE6]. While it could be argued that “PhoneNumber@163b91” is concise and easy to read, it isn’t very informative when compared to “(707) 867-5309.” The toString
contract goes on to say, “It is recommended that all subclasses override this method.” Good advice, indeed!
盡管java.lang.Object
提供了toString
方法的實現(xiàn)陨倡,但是通常情況下它返回的字符串不是使用類的用戶想要的症见。返回的字符串包含類名垒探,后面是一個@
符號加上哈希碼的十六進制表示,例如PhoneNumber@163b91
匙瘪。toString
的通用約定指出醉顽,返回值應(yīng)該是“簡潔但易讀的信息表示”[JavaSE6]羊赵。雖然可以認(rèn)為PhoneNumber@163b91
簡潔易讀独悴,但它與(707) 867-5309
相比,它的信息不夠豐富混驰。toString
約定進一步指出攀隔,“建議所有的子類重寫這個方法”。確實是個好建議栖榨。
While it isn’t as important as obeying the equals
and hashCode
contracts (Item 8, Item 9), providing a good toString
implementation makes your class much more pleasant to use. The toString
method is automatically invoked when an object is passed to println
, printf
, the string concatenation operator, or assert
, or printed by a debugger. (The printf
method was added to the platform in release 1.5, as were related methods including String.format
, which is roughly equivalent to C’s sprintf
.)
雖然它不像遵守equals
和hashCode
約定(Item 8, Item 9)那樣重要昆汹,但是提供一個好的toString
實現(xiàn)可以使你的類用起來更舒適。當(dāng)對象傳到println
婴栽,printf
满粗,字符串連接操作符,或assert
中愚争,或通過調(diào)試器打印時映皆,會自動調(diào)用toString
方法挤聘。(Java 1.5版本中平臺加入了printf
方法,相關(guān)的方法包括String.format
捅彻,類似于C語言中的sprintf
方法)组去。
If you’ve provided a good toString
method for PhoneNumber
, generating a useful diagnostic message is as easy as this:
如果你已經(jīng)為PhoneNumber
提供了一個好的toString
方法,生成有用的診斷信息是很容易的:
System.out.println("Failed to connect: " + phoneNumber);
Programmers will generate diagnostic messages in this fashion whether or not you override toString
, but the messages won’t be useful unless you do. The benefits of providing a good toString
method extend beyond instances of the class to objects containing references to these instances, especially collections. Which would you rather see when printing a map, “{Jenny=PhoneNumber@163b91}” or “{Jenny=(707) 867-5309}”?
無論你是否重寫toString
方法步淹,程序員們都會以這種方式生成診斷信息从隆,但除非你重寫了toString
方法,否則這些信息是無用的贤旷。提供一個好的toString
方法的好處是除了類的實例之外广料,也擴展了包含這些實例引用的對象砾脑,尤其是集合幼驶。當(dāng)打印一個映射時,{Jenny=PhoneNumber@163b91}
或{Jenny=(707) 867-5309}
你更喜歡哪一個韧衣?
When practical, the toString
method should return all of the interesting information contained in the object, as in the phone number example just shown. It is impractical if the object is large or if it contains state that is not conducive to string representation. Under these circumstances, toString
should return a summary such as “Manhattan white pages (1487536 listings)” or “Thread[main,5,main]”. Ideally, the string should be self-explanatory. (The Thread
example flunks this test.)
當(dāng)實踐時盅藻,toString
方法應(yīng)該返回包含在對象中的所有的感興趣信息,正如剛才電話號碼的例子展示的那樣畅铭。如果對象很大或它包含不能用字符串表示的狀態(tài)氏淑,重寫toString
方法是不切實際的。在這種情況下硕噩,toString
應(yīng)該返回一個概要信息假残,例如Manhattan white pages (1487536 listings)
或Thread[main,5,main]
。理想情況下炉擅,字符串應(yīng)該是自解釋的辉懒。(Thread
例子不能滿足這樣的要求。)
One important decision you’ll have to make when implementing a toString
method is whether to specify the format of the return value in the documentation. It is recommended that you do this for value classes, such as phone numbers or matrices. The advantage of specifying the format is that it serves as a standard, unambiguous, human-readable representation of the object. This representation can be used for input and output and in persistent human-readable data objects, such as XML documents. If you specify the format, it’s usually a good idea to provide a matching static factory or constructor so programmers can easily translate back and forth between the object and its string representation. This approach is taken by many value classes in the Java platform libraries, including BigInteger
, BigDecimal
, and most of the boxed primitive classes.
當(dāng)實現(xiàn)toString
時谍失,你要做的一個重要決定是是否在文檔中指定返回值的格式眶俩。對于值類建議你這樣做,例如電話號碼或矩陣快鱼。指定返回值格式的優(yōu)勢在于它能為對象提供一個標(biāo)準(zhǔn)的颠印,清晰的,可讀的表示抹竹。這個表示可以用在輸入輸出中线罕,也可以用在一致的可讀數(shù)據(jù)對象中,例如XML文檔窃判。如果你指定了格式闻坚,提供一個匹配的靜態(tài)工廠或構(gòu)造函數(shù)通常是一個好主意,程序員可以很容易地在對象和它的字符串表示之間來回轉(zhuǎn)換兢孝。Java平臺庫中許多值類都采用了這個方法窿凤,包括BigInteger
仅偎,BigDecimal
和大多數(shù)基本類型的包裝類。
The disadvantage of specifying the format of the toString
return value is that once you’ve specified it, you’re stuck with it for life, assuming your class is widely used. Programmers will write code to parse the representation, to generate it, and to embed it into persistent data. If you change the representation in a future release, you’ll break their code and data, and they will yowl. By failing to specify a format, you preserve the flexibility to add information or improve the format in a subsequent release.
指定toString
返回值格式的劣勢在于一旦你指定了它雳殊,假設(shè)你的類被廣泛使用橘沥,你就必須一直堅持它。程序員將會寫代碼轉(zhuǎn)換這種表示夯秃,產(chǎn)生這種格式并將它嵌入到持久化數(shù)據(jù)中座咆。如果你在將來的版本中更改了表示格式,你將會破壞他們的代碼和數(shù)據(jù)仓洼,他們將會抱怨介陶。如果你沒有指定格式,你保留了添加信息的靈活性或者在后續(xù)版本改進這種格式色建。
Whether or not you decide to specify the format, you should clearly document your intentions. If you specify the format, you should do so precisely. For example, here’s a toString
method to go with the PhoneNumber
class in Item 9:
無論你決定是否指定格式哺呜,你都應(yīng)該清楚地表明你的意圖。如果你指定了格式箕戳,你應(yīng)該準(zhǔn)確的去做某残。例如,下面的Item 9中PhoneNumber
類的toString
方法:
/**
* Returns the string representation of this phone number.
* The string consists of fourteen characters whose format
* is "(XXX) YYY-ZZZZ", where XXX is the area code, YYY is
* the prefix, and ZZZZ is the line number. (Each of the
* capital letters represents a single decimal digit.)
*
* If any of the three parts of this phone number is too small
* to fill up its field, the field is padded with leading zeros.
* For example, if the value of the line number is 123, the last * four characters of the string representation will be "0123". *
* Note that there is a single space separating the closing
s* parenthesis after the area code from the first digit of the * prefix.
*/
@Override public String toString() {
return String.format("(%03d) %03d-%04d",areaCode, prefix, lineNumber);
}
If you decide not to specify a format, the documentation comment should read something like this:
如果你沒有指定格式陵吸,文檔注釋讀起來應(yīng)該如下:
/**
* Returns a brief description of this potion. The exact details * of the representation are unspecified and subject to change, * but the following may be regarded as typical:
*
* "[Potion #9: type=love, smell=turpentine, look=india ink]" */
@Override public String toString() { ... }
After reading this comment, programmers who produce code or persistent data that depends on the details of the format will have no one but themselves to blame when the format is changed.
寫代碼或持久化數(shù)據(jù)的依賴于格式細(xì)節(jié)的程序員玻墅,在讀了這個文檔之后,一旦格式改變壮虫,只能自己負(fù)責(zé)后果澳厢。
Whether or not you specify the format,** provide programmatic access to all of the information contained in the value returned by toString
**. For example, the PhoneNumber
class should contain accessors for the area code, prefix, and line number. If you fail to do this, you force programmers who need this information to parse the string. Besides reducing performance and making unnecessary work for programmers, this process is error-prone and results in fragile systems that break if you change the format. By failing to provide accessors, you turn the string format into a de facto API, even if you’ve specified that it’s subject to change.
無論你是否指定了格式,都應(yīng)該提供toString
返回值中包含的所有信息的程序訪問接口囚似。例如剩拢,PhoneNumber
類應(yīng)該包含區(qū)域碼,前綴和行號的訪問器谆构。如果你沒有這樣做裸扶,你會迫使需要這個信息的程序員取轉(zhuǎn)換這個字符串。除了為程序員降低效率和造成不必要的工作之外搬素,這個過程中很容易出錯呵晨,而且會導(dǎo)致系統(tǒng)非常脆弱,如果你更改了格式系統(tǒng)會崩潰熬尺。如果沒有提供訪問器摸屠,即使你指明了字符串格式是可以變化的,這個字符串格式也變成了實際上的API粱哼。