文章作者:Tyan
博客:noahsnail.com | CSDN | 簡書
Item10: 總是重寫toString方法
盡管java.lang.Object
提供了toString
方法的實現(xiàn)恨旱,但是通常情況下它返回的字符串不是使用類的用戶想要的深浮。返回的字符串包含類名岳守,后面是一個@
符號加上哈希碼的十六進制表示敲霍,例如PhoneNumber@163b91
。toString
的通用約定指出蝇刀,返回值應(yīng)該是“簡潔但易讀的信息表示”[JavaSE6]骏庸。雖然可以認為PhoneNumber@163b91
簡潔易讀杂数,但它與(707) 867-5309
相比,它的信息不夠豐富锉试。toString
約定進一步指出猫十,“建議所有的子類重寫這個方法”。確實是個好建議呆盖。
雖然它不像遵守equals
和hashCode
約定(Item 8, Item 9)那樣重要炫彩,但是提供一個好的toString
實現(xiàn)可以使你的類用起來更舒適。當對象傳到println
絮短,printf
江兢,字符串連接操作符,或assert
中丁频,或通過調(diào)試器打印時杉允,會自動調(diào)用toString
方法。(Java 1.5版本中平臺加入了printf
方法席里,相關(guān)的方法包括String.format
叔磷,類似于C語言中的sprintf
方法)。
如果你已經(jīng)為PhoneNumber
提供了一個好的toString
方法奖磁,生成有用的診斷信息是很容易的:
System.out.println("Failed to connect: " + phoneNumber);
無論你是否重寫toString
方法改基,程序員們都會以這種方式生成診斷信息,但除非你重寫了toString
方法咖为,否則這些信息是無用的秕狰。提供一個好的toString
方法的好處是除了類的實例之外,也擴展了包含這些實例引用的對象躁染,尤其是集合鸣哀。當打印一個映射時,{Jenny=PhoneNumber@163b91}
或{Jenny=(707) 867-5309}
你更喜歡哪一個吞彤?
當實踐時我衬,toString
方法應(yīng)該返回包含在對象中的所有的感興趣信息叹放,正如剛才電話號碼的例子展示的那樣。如果對象很大或它包含不能用字符串表示的狀態(tài)挠羔,重寫toString
方法是不切實際的井仰。在這種情況下,toString
應(yīng)該返回一個概要信息破加,例如Manhattan white pages (1487536 listings)
或Thread[main,5,main]
俱恶。理想情況下,字符串應(yīng)該是自解釋的拌喉。(Thread
例子不能滿足這樣的要求速那。)
當實現(xiàn)toString
時,你要做的一個重要決定是是否在文檔中指定返回值的形式尿背。對于值類建議你這樣做端仰,例如電話號碼或矩陣。指定返回值形式的優(yōu)勢在于它能為對象提供一個標準的田藐,清晰的荔烧,可讀的表示。這個表示可以用在輸入輸出中汽久,也可以用在一致的可讀數(shù)據(jù)對象中鹤竭,例如XML文檔。如果你指定了這個形式景醇,提供一個匹配的靜態(tài)工廠或構(gòu)造函數(shù)通常是一個好主意臀稚,程序員可以很容易地在對象和它的字符串表示之間來回轉(zhuǎn)換。Java平臺庫中許多值類都采用了這個方法三痰,包括BigInteger
吧寺,BigDecimal
和大多數(shù)基本類型的包裝類。
指定toString
返回值形式的劣勢在于一旦你指定了它散劫,假設(shè)你的類被廣泛使用稚机,你就必須一直堅持它。程序員將會寫代碼轉(zhuǎn)換這種表示获搏,產(chǎn)生這種形式并將它嵌入到持久化數(shù)據(jù)中赖条。如果你在將來的版本中更改了表示形式,你將會破壞他們的代碼和數(shù)據(jù)常熙,他們將會抱怨纬乍。如果你沒有指定一個形式,你保留了添加信息的靈活性或者在后續(xù)版本改進這種形式症概。
無論你決定是否指定格式蕾额,你都應(yīng)該清楚地表明你的意圖。如果你指定了格式彼城,你應(yīng)該準確的去做。例如,下面的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);
}
如果你沒有指定格式募壕,文檔注釋讀起來應(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() { ... }
寫代碼或持久化數(shù)據(jù)的依賴于格式細節(jié)的程序員调炬,在讀了這個文檔之后,一旦格式改變舱馅,只能自己負責(zé)后果缰泡。
無論你是否指定了格式,都應(yīng)該提供toString
返回值中包含的所有信息的程序訪問接口代嗤。例如棘钞,PhoneNumber
類應(yīng)該包含區(qū)域碼,前綴和行號的訪問器干毅。如果你沒有這樣做宜猜,你會迫使需要這個信息的程序員取轉(zhuǎn)換這個字符串。除了為程序員降低效率和造成不必要的工作之外硝逢,這個過程中很容易出錯姨拥,而且會導(dǎo)致系統(tǒng)非常脆弱,如果你更改了格式系統(tǒng)會崩潰渠鸽。如果沒有提供訪問器叫乌,即使你指明了字符串格式是可以變化的,這個字符串格式也變成了實際上的API徽缚。