Effective Java Item12 - 始終要覆蓋toString
June 24, 2018這篇是Effective Java - Always override toString章節的讀書筆記 本篇的程式碼來自於原書內容
Item12: 始終要覆蓋toString
為何要複寫toString
雖然java.lang.Object有提供toString方法的實現 但他返回的字符串長得像這樣
PhoneNumber@163b91
就是類的名稱 + @ + 一個hash 這也很明顯就是要你自己複寫 最好是能寫成一個 簡潔 信息豐富 易於閱讀 的形式
雖然覆蓋toString的約定不像遵守equals和hashCode的約定那麼重要 但是提供好的toString可以讓類的使用更加舒適 比如說傳進println,字串連結符(+), assert 或是debuger
比如說你今天要debug
System.out.println(“Failed to call “ + phoneNumber)
你想看到的是
PhoneNumber@163b91
還是
(408) 867-5309
要怎麼複寫
實際應用中 toString應該返回對象中包含的值得關注的信息 最少要包含equals裡比較的每一個關鍵域
你總不希望在unit test看到
Assertion failure: expected {abc, 123}, but was {abc, 123}
吧
是否在文檔指定格式
在實現toString的時候 必須要做個重要決定 就是要不要在文檔中指定返回值的格式
好處: 1.用作一種標準的 明確的 適合人閱讀的對象表示法 可以用於輸入輸出 也可以存儲在適合人類閱讀的檔案文件中(比如xml)
2.最好再搭配一個靜態工廠或構造器 這樣使用者就可以輕鬆地在對象以及表示法之間來回轉換 java裡面已經有很多類別都這麼做了 比如說BigInteger BigDecimal和boxed primitive type
壞處: 一但指定格式 生生世世都必須遵守 因為你的使用者會寫程式去解析字串表示法 或是用來存儲
不論你要不要在文檔指定 都要在文檔表明意圖以及為什麼
直接看電話號碼的例子
/**
* 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
* 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);
}
如果你不想指定格式 你可以再加一段
/**
* Returns a brief description of this phone number. The exact
* details of the representation are unspecified and subject
* to change, but the following may be regarded as typical:
*
* "(707) 867-5309"
*
*/
這樣如果有程序員去過度使用你的格式 那在格式改變之後 就只能自行承擔後果
這也代表說當你在用某個類別時 你不該過度依賴一個類別的格式 比如說太過依賴格式的細節 進行存儲或是parsing
提供api
別忘了所有你在toString有用到的域 都要提供getter 比如說你一定要有getPrefix, getAreaCode和getLineNumber
否則的話你也是在強迫你的使用者去parse你的字串格式
不需要複寫toString的情況
static utility class
enum type
總結
除非你的superclass已經寫好了toString 不然你應該在每個可以被實例化的類別寫toString toString方法應該回傳一個簡潔好用的物件描述 這會讓你的類別更好用 更好開發和除錯