자바에서 최상위 객체인 Object는 하위 객체들이 오버라이딩하여 사용하도록 설계된 메서드들이 있다. (equals, hashCode, toString, clone, finalize) 그리고 이 메서드들은 일반 규약이 존재하는데 이를 따르지 않으면 자바에서 제공하는 클래스와 함께 사용할 때 제대로 동작하지 않는다.
이번 장에서는 toString 메서드에 대해 설명한다.
Object.toString() 메서드
Object.toString() 메서드는 print와 같은 함수, assert, debugger 등에 객체가 전달되면 자동으로 호출되는 메서드로 해당 객체의 대한 정보를 사람이 읽기 쉽도록 간략하지만 유용한 정보를 제공하도록 하는 메서드이다.
하지만 Object 클래스에 정의된 toString() 메서드는 클래스 이름 다음에 @ 기호와 16진수로 표현된 해시 코드가 붙은 문자열을 출력하도록 아래와 같이 구현되어 있다.
public class Object {
...
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
따라서 toString() 명세서에는 다음과 같이 작성되어 있다.
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.
toString 메서드 구현 방법
1. 가능하다면 객체 내의 중요 정보를 전부 담자.
2. 중요 정보가 너무 많다면 최대한 요약해 표현하자.
3. 표현되는 정보들은 getter와 같은 메서드를 제공하여 정보를 가져갈 수 있도록 하자.
4. 누군가는 toString이 리턴하는 문자열을 파싱하여 사용할 수 있다. 따라서 항상 명세서에 toString이 리턴하는 문자열에 대해 자세히 표현한다.
아래는 9장에서 사용한 클래스의 toString의 예제이다.
public class PhoneNumberWithHashCode {
private final int areaCode;
private final int prefix;
private final int lineNumber;
public PhoneNumberWithHashCode(int areaCode, int prefix, int lineNumber) {
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
}
/**
*
* 전화번호를 문자열로 변환해서 반환한다.
* 문자열은 "(XXX) YYY-ZZZZ" 형식으로 표현하여, 지역번호(areaCode), 국번(prefix), 회선번호(lineNumber) 순이다.
* 형식은 변경될 수 있다.
*/
@Override
public String toString() {
return String.format("(%03d) %03d-%04d", areaCode, prefix, lineNumber);
}
public static void main(String[] args) {
PhoneNumberWithHashCode p1 = new PhoneNumberWithHashCode(111, 654, 7009);
System.out.println(p1);
}
}
아래는 자주 사용하는 API들에 대한 toString 소스이다.
- java.util.AbstractMap : 대부분의 *Map들이 상속하는 클래스
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
System.out.println(map.toString()); // {key1=value1, key2=value2}
/**
* Returns a string representation of this map. The string representation
* consists of a list of key-value mappings in the order returned by the
* map's <tt>entrySet</tt> view's iterator, enclosed in braces
* (<tt>"{}"</tt>). Adjacent mappings are separated by the characters
* <tt>", "</tt> (comma and space). Each key-value mapping is rendered as
* the key followed by an equals sign (<tt>"="</tt>) followed by the
* associated value. Keys and values are converted to strings as by
* {@link String#valueOf(Object)}.
*
* @return a string representation of this map
*/
public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
sb.append(key == this ? "(this Map)" : key);
sb.append('=');
sb.append(value == this ? "(this Map)" : value);
if (! i.hasNext())
return sb.append('}').toString();
sb.append(',').append(' ');
}
}
- java.util.Date : 날짜 및 시각 정보를 관리하는 클래스
System.out.println(new Date().toString()); // Mon Dec 13 23:46:32 KST 2021
/**
* Converts this <code>Date</code> object to a <code>String</code>
* of the form:
* <blockquote><pre>
* dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
* where:<ul>
* <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
* Thu, Fri, Sat</tt>).
* <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
* Jul, Aug, Sep, Oct, Nov, Dec</tt>).
* <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
* <tt>31</tt>), as two decimal digits.
* <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
* <tt>23</tt>), as two decimal digits.
* <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
* <tt>59</tt>), as two decimal digits.
* <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
* <tt>61</tt>, as two decimal digits.
* <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
* time). Standard time zone abbreviations include those
* recognized by the method <tt>parse</tt>. If time zone
* information is not available, then <tt>zzz</tt> is empty -
* that is, it consists of no characters at all.
* <li><tt>yyyy</tt> is the year, as four decimal digits.
* </ul>
*
* @return a string representation of this date.
* @see java.util.Date#toLocaleString()
* @see java.util.Date#toGMTString()
*/
public String toString() {
// "EEE MMM dd HH:mm:ss zzz yyyy";
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
if (index == BaseCalendar.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
sb.append(' ').append(date.getYear()); // yyyy
return sb.toString();
}
'Java > [책] 이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] 규칙12. Comparable, Comparator 인터페이스 (0) | 2022.01.07 |
---|---|
[이펙티브 자바] 규칙11. Object.clone() 구현방법 (0) | 2021.12.28 |
[이펙티브 자바] 규칙9. Object.hashCode() 구현방법 (0) | 2021.11.28 |
[이펙티브 자바] 규칙8. Object.equals() 구현방법 (0) | 2021.11.23 |
[이펙티브 자바] 규칙7. GC가 호출하는 Object.finalize() (0) | 2021.11.14 |