카테고리:

업데이트:

1. 들어가기

toString 메서드는 해당 객체의 정보를 알 수 있는 메서드입니다.

Object의 기본 toString 메서드는 단순히 PhoneNumber@b4c966a 형태로 반환합니다.

객체에 대한 정보를 알고 싶은 프로그래머에게는 유용하지 않은 정보인 것이죠.

그래서 toString의 규약에 “모든 하위 클래스에서 이 메서드를 재정의하라” 가 있습니다.

그렇다면 toString 메서드를 어떻게 재정의해야 프로그래머에게 유용한 정보를 제공할 수 있을까요?

2. toString 메서드 재정의 방법

  1. 그 객체가 가진 주요 정보 모두를 반환하는 것이 좋다.

    toString 메서드를 재정의할 때는 되도록 그 객체가 가진 정보를 모두 반환해야 합니다.

     static class Person {
       String name;
       int age;
       String gender;
    
       // 생성자 생략
    
       @Override
       public String toString() {
           return "Person{" +
                   "name='" + name + '\'' +
                   ", age=" + age +
                   ", gender='" + gender + '\'' +
                   "}";
       }
     }
    
     Person{name='이상훈', age=28, gender='Men'}
    

    하지만, 객체가 거대하거나 객체의 상태가 문자열로 표현하기에 적합하지 않는 경우가 있습니다.

    이런 상황이라면 맨해튼 거주자 전화번호부 (총 1467개) 와 같이 객체의 요약 정보를 담으면 됩니다.

  2. 반환값의 포맷을 문서화할지 정한다.

    전화번호나 행렬 같은 값 클래스라면 문서화하는 것이 좋습니다.

    포맷을 명시하면 그 객체는 표준적이고, 명확하며 사람이 읽을 수 있게 됩니다.

    포맷을 명시하기로 했다면,

    명시한 포맷에 맞는 문자열과 객체를 정적 팩터리나 생성자를 함께 제공해주면 좋습니다.

  3. 의도를 명확히 밝혀야 한다.

    해당 toString의 생성 의도에 따라 프로그래머들은 사용 여부를 결정할 수 있습니다.

     /**
     * 이 전화번호의 문자열 표현을 반환한다.
     * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 12글자로 구성된다.
     * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호이다.
     * 각각의 대문자는 10진수 숫자 하나를 나타낸다.
     *
     * 전화번호의 각 부분 값이 너무 작아서 자릿수를 채울 수 없다면,
     * 앞에서부터 0으로 채워나간다. 예컨대 가입자 번호가 123이라면
     * 전화번호의 마지막 네 문자는 0123이다.
     */
     @Override
     public String toString() {
       return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
     }
    
     /**
     * 이 약물에 관한 대략적인 설명을 반환한다.
     * 다음은 이 설명의 일반적인 형태이나,
     * 상세 형식은 정해지지 않았으며 향후 변경될 수 있다.
     *
     * "[약물 #9: 유형=사랑, 냄새=테레빈유, 겉모습=먹물]"
     */
     @Override public String toString() {
       return "[약물 " + id + ": " +
              "유형=" + type + "," +
              "냄새=" + smell + "," +
              "겉모습=" + shape +
              "]";
     }
    

3. toString 재정의 시 주의사항

이번에는 toString 재정의 시에 주의해야할 사항을 알아봅시다.

  1. toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공해야 한다.

    toString 메서드가 반환한 값은 모두 제공해야 합니다.

    그렇지 않는다면 프로그래머들은 toString의 반환값을 파싱할 수 밖에 없습니다.

    예를 들면 다음과 같이 말이죠.

    /* 클래스의 toString 메서드 */
     @Override
     public String toString() {
       return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
     }
    
    /* 프로그래머가 작성한 getter */
     public String getAreaCode() {
       return phoneNumber.toString().substring(0, 3);
     }
    

    이는 성능이 나빠지고, 필요하지도 않은 작업입니다.

    게다가 향후 포맷을 변경하면 시스템이 망가지는 결과를 초래할 수도 있습니다.

  2. 정적 유틸리티 클래스는 toString을 제공할 이유가 없다.

  3. 대부분의 열거타입도 재정의할 필요가 없다.

    이는 Java가 열거 타입에 대해서 이미 완벽한 toString 메서드를 제공하기 때문입니다.

    단, 하위 클래스들이 공유해야 할 문자열 표현이 있는 경우에는 재정의해줘야 합니다.

4. 정리

이번 포스트에서는 객체의 정보를 알 수 있는 toString 메서드에 대해서 알아보았습니다.

Object의 toString 메서드는 프로그래머에게 유용하지 않은 정보를 제공하기 때문에

모든 구체 클래스에서 Object의 toString 메서드를 재정의하는 것이 좋습니다.

하지만 상위 클래스에서 이미 알맞게 정의했고,

하위 클래스에서도 들어맞다면 다시 재정의할 필요는 없습니다.

toString 메서드는 객체 사용에 편리하고, 시스템 디버깅이 용이하므로

해당 객체에 관한 명확하고 유용한 정보를 읽기 좋은 형태로 재정의하는 것이 좋습니다.

            
              📕 개인 기록용 블로그입니다.
              😊 오타나 잘못된 정보가 있을 경우 댓글이나 메일로 말씀해주시면 바로 수정하겠습니다! 😊
          

댓글남기기