"SomeType@2f92e0f4"와 같은 값이 아닌 자바 객체의 데이터를 어떻게 출력할 수 있을까요?

조회수 14625회

다음과 같은 클래스를 정의하였습니다:

public class Person {
  private String name;

  // constructor and getter/setter omitted
}

이 Person 클래스의 객체를 출력해보았습니다.

System.out.println(myPerson);

출력값: com.foo.Person@2f92e0f4

Person 클래스의 객체들을 갖는 배열을 출력할 때도 비슷한 결과값이 출력되었습니다.

Person[] people = //...
System.out.println(people); 

출력값: [Lcom.foo.Person;@28a418fc

출력값의 의미는 무엇인가요? Person 클래스 객체의 name 필드의 값을 갖도록 하려면 어떻게 수정해야 하나요? 그리고 객체들의 배열의 값을 출력은 어떻게 해야 하나요?

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    기본개념

    자바의 모든 객체는 toString() 메소드를 가집니다. 그리고 객체의 값을 출력하고자 할 때 그 메소드를 자동 호출합니다.

    System.out.println(myObject);  // invokes myObject.toString()
    

    이 메소드는 자바의 모든 클래스의 슈퍼 클래스인 [Object](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html) 클래스가 정의하였습니다. Object.toString() 메소드는 이상하게 생긴 문자열을 반환합니다. 그 이상한 문자열은 클래스의 이름, @ 문자 그리고 16진수로 표현된 객체의 hashcode로 이루어집니다. Object 클래스의 toString() 메소드는 다음과 같이 정의되어 있습니다.

    // Code of Object.toString()
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    

    그러므로 출력값 com.foo.MyType@2f92e0f4은 다음과 같은 의미를 내포하고 있는 것이지요.

    • com.foo.MyType - 클래스의 이름. 즉, com.foo. 패키지의 MyType 클래스
    • @ - 문자열 구분자
    • 2f92e0f4 - 객체의 hashcode

    Javadoc의 Class.getName()에 잘 설명된 것 같이, 배열 클래스의 이름은 조금 다르게 표현됩니다. 예를 들어 [Ljava.lang.String의 의미는 다음과 같습니다.

    • [ - 1차원 배열을 나타냅니다 (2차원 배열: [[, 3차원 배열: [[[ 등)
    • L - 클래스 또는 인터페이스를 포함하는 배열 인지를 의미합니다.
    • java.lang.String - 배열 안에 저장된 객체의 타입

    출력값 정의하기

    System.out.println(myObject)를 호출할 때 다르게 출력하기 위해서는 `toString() 메소드를 해당 클래스 내에서 오버라이드 해야 합니다. 다음은 간단한 예입니다:

    public class Person {
    
      private String name;
    
      // constructors and other methods omitted
    
      @Override
      public String toString() {
        return name;
      }
    }
    

    그러면 Person 클래스의 객체를 출력할 때, com.foo.Person@12345678 대신에 해당 객체의 name 필드의 값이 출력될 것입니다.

    toString()은 객체를 문자열로 변환할 수 있는 하나의 방법인 것을 기억하세요. 일반적으로 이 출력값은 명확하고 간결한 방식으로 객체의 데이터 전체를 설명할 수 있어야 합니다. 그래서 Person 클래스의 toString() 메소드를 다음과 같이 정의하는 것이 더 좋습니다:

    @Override
    public String toString() {
      return getClass().getSimpleName() + "[name=" + name + "]";
    }
    

    출력값의 예: Person[name=Henry] 이 값은 디버깅하거나 테스트 할 때 굉장히 유용하게 활용될 수 있습니다.

    만약 객체의 데이터 중 한 측면에 초점을 맞추거나 좀 더 화려한 형식을 지정하고자 한다면, toString() 메소드와 구분되는 다른 메소드(예: String toElegantReport()')를 정의하는 것도 좋습니다.


    출력값을 자동 생성하기

    많은 IDE들은 해당 클래에 정의된 필드들을 기반으로 toString() 메소드를 자동 생성하는 기능을 제공합니다. EclipseIntelliJ와 같은 IDE의 문서들을 확인해보세요.

    몇가지 유명한 자바 라이브러리들도 이 기능을 제공합니다. 예를 들면 다음과 같습니다.


    객체들의 그룹을 출력하기

    이제 클래스를 정의할 때 toString()을 잘 정의하실 수 있겠지요. 그럼 배열 혹은 컬렉션 내의 클래스에 대해서는 어떻게 처리해야 할까요?

    배열

    객체의 배열에 대해서, 배열의 데이터를 간단하게 표현하고자 한다면 Arrays.toString() 메소드를 호출할 수 있습니다. 예를 들어 Person 객체 배열을 생각해 보면:

    Person[] people = { new Person("Fred"), new Person("Mike") };
    System.out.println(Arrays.toString(people));
    
    // Prints: [Fred, Mike]
    

    주의: 이것은 이제까지 논의해왔던 Object 클래스의 toString()이 아니라, Array 클래스의 toString()이라는 static 메소드를 호출한 것입니다.

    만약 다차원 배열을 사용한다면, 위와 같은 똑같은 형식의 출력값을 얻기 위해서 Arrays.deepToString() 메소드를 사용하면 됩니다.

    컬렉션

    대부분의 컬렉션은 모든 원소에 대해서 .toString() 메소드를 사용해서 보기 좋은 출력을 생성할 수 있습니다.

    List<Person> people = new ArrayList<>();
    people.add(new Person("Alice"));
    people.add(new Person("Bob"));    
    System.out.println(people);
    
    // Prints [Alice, Bob]
    

    그래서 위에서 설명한 것처럼 컬렉션 각각의 요소들마다 toString() 메소드를 잘 정의할 필요가 있습니다.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)