Java - 객체를 문자로 표현하는 toString()을 잘 사용하는 방법

자바에서는 객체를 문자화 시킬 때  toString()을 사용합니다. 대부분 사람들이 처음 toString()을 배울 때 단순한 출력문 함께 배우기 때문에 toString()을 인스턴스를 표현하는 @어쩌고의 문자 값 정도로 인지하지만 알고 보면 재미있는 녀석이 toString()입니다.

 

 toString()은 객체의 단순하게 보면 문자 값이지만, 객체의 입장에서 본다면 인스턴스화 된 자신을 문자로 표현할 수 있는 Object의 유산이에요. toString()을 잘 사용한다면 조금 더 재미있게 객체의 관점에서 객체를 바라볼 수 있어요. Object가 물려준 유산이 toString() 외에도 여러 가지가 있지만 오늘은 toString()에 대해서 이야기해보겠습니다.

toString()은 어디에 사용될까? - 내 이름을 불러 줘

 toString()을 있는 그대로 해석하면 문자 값으로 라는 의미를 가집니다. 문자 값으로..? 무엇을 문자 값으로 한다는 이야기일까요? 바로 클래스가 아닌 인스턴스가 가진 무언가를 말이죠. 클래스는 같을지 몰라도 new 연산자를 통해 만들어진 인스턴스화 된 객체는 저마다 가지고 있는 값이 다릅니다.

package example.step1;

class Person {
  private String name;

  public Person(String name) {
    this.name = name;
  }
}

public class Main {

  public static void main(String[] args) {
    Person person1 = new Person("홍길동");
    Person person2 = new Person("아무개");

    System.out.println(person1);
    // example.step1.Person@2a139a55
    
    System.out.println(person2);
    // example.step1.Person@15db9742
  }
}

 물론 사람들마다 가지는 이름이 같을 때도 있는 것처럼 객체가 가진 값이 항상 다르지는 않습니다. 하지만 객체가 가진 값이 같든 다르든 인스턴스화 된 객체가 저마다 값을 지니고 있다는 사실을 바뀌지 않습니다. 그리고 그 객체를 들여다보는 방법은 흔히 사용하는 게터(getter)를 제외하면 거의 없습니다.

package example.step2;

class Person {
  ...
  
  public String getName() {
    return name;
  }
}

public class Main {

  public static void main(String[] args) {
    Person person1 = new Person("홍길동");
    Person person2 = new Person("홍길동");

    System.out.println(person1);
    // example.step2.Person@2a139a55
    System.out.println(person1.getName());
    // 홍길동
    
    System.out.println(person2);
    // example.step2.Person@15db9742
    System.out.println(person2.getName());
    // 홍길동
  }
}

 그렇기 때문에 객체는 누군가 메서드를 통해 물어보지 않는 이상 주체적으로 자신 다움을 표현할 수 있는 방법이 없습니다. toString()을 제외하고는 말이죠. toString()도 어디선가 호출해야 되는 게 아니냐고 물으신다면 틀린 말은 아닙니다. 다만 System.out.println()와 같이 객체를 문자 값으로 치부해 사용하는 경우에 toString()이 자연스럽게 호출됩니다.

package example.step3;

class Person {
  ...
  
  @Override
  public String toString() {
    return "내 이름은 " + name + " 입니다.";
  }
}

public class Main {

  public static void main(String[] args) {
    Person person1 = new Person("홍길동");
    Person person2 = new Person("아무개");

    System.out.println(person1);
    // 내 이름은 홍길동 입니다.
    
    System.out.println(person2);
    // 내 이름은 아무개 입니다.
  }
}

 이건 자바에서 정의한 규칙이에요. 이렇게 규칙을 정의한 이유는 객체는 사용자가 마음대로 정의하고 사용할 수 있기 때문입니다. toString()과 같은 약속이 없으면 객체를 문자로 정의하고 쓰고 싶을 때 사용할 수 있는 방법이 없어요. 그런 연유로 자바에서는 객체의 문자 값이 필요한 경우 toString()이 호출되게 설계되어 있습니다. 결국 toString()은 객체가 문자로 취급될 때 사용되는 메서드로 객체가 자신의 정체성을 드러내는 하나의 수단입니다. 

toString()을 재정의(Overriding) 해볼까? - Object가 가진 toString()

 앞서 toString()이 어떤 이유로 어디서 사용되는지 알아보았습니다. 이번에는 toString()을 재정의하는 방법에 대해 알아보겠습니다.

class Person {

  private String name;

  private String job;

  public Person(String name, String job) {
    this.name = name;
    this.job = job;
  }

  @Override
  public String toString() {
    return "내 이름은 " + name + "이고, 직업은 " + job + "입니다.";
  }
}

public class Main {

  public static void main(String[] args) {
    Person person = new Person("홍길동", "의적");

    System.out.println(person);
    // 내 이름은 홍길동이고, 직업은 의적입니다.
  }
}

이번에는 기존 예제에 직업(job)이라는 변수를 추가하고 toString()을 통해 이름(nane)과 직업이 같이 보일 수 있도록 해보았습니다. toString()을 재정의하는 방법은 예제 코드와 같습니다. 클래스에 public 접근 제한자를 가지고 String을 반환하는 toString() 메서드를 정의하면 됩니다. @Override 에노테이션은 사용하지 않아도 메서드를 재정의 할 수 있지만 되도록이면 사용해주세요.

 

 자바에서 모든 클래스가 toString()을 재정의 할 수 있는 이유는 exnteds로 Object 클래스를 상속하지 않아도 기본으로 Object를 부모 클래스로 사용하고 있기 때문입니다. 또한 Object는 자신을 문자로 나타내는 메서드인 toString()을 가지고 있습니다. 그렇기 때문에 모든 클래스는 toString()을 사용할 수 있고, 자신에 맞게 사용하기 위해서는 재정의(Overriding)를 해야 합니다.

hello-java-example-to-string.zip
0.06MB

 본문에서 사용한 예제 내용은 첨부파일과 Github을 통해서 제공하니 필요하신 분은 가져가서 사용하시면 됩니다.

끝맺음

 객체를 문자 값으로 표현하는 방법을 toString()으로 한정할 수는 없지만, 게터(getter) 혹은 새로운 메서드를 추가해서 사용하는 것보다는 이미 모든 객체가 가지고 있는 toString()을 활용한다면 보다 사물의 관점에서 객체를 문자로 사용할 수 있습니다.

 

 어디선가 나(객체)를 부르면 딱딱하게(Person2@2a139a55) 보여주는 대신 toString()을 재정의해서 자신을 표현해보면 어떨까요?

반응형

댓글

Designed by JB FACTORY