toString() 메서드

hoon·2025년 1월 13일

JAVA

목록 보기
3/21

toString() 메서드

toString() 메서드는 자바에서 모든 클래스의 부모 클래스인 Object 클래스에 정의된 메서드입니다. 객체를 문자열(String)로 표현할 때 사용되며, 객체의 정보나 상태를 출력하거나 디버깅할 때 유용합니다.


1. 기본 정의

  • toString() 메서드의 선언:
    public String toString()
    
  • 기본 동작:
    • Object 클래스의 기본 toString() 구현은 클래스 이름16진수 해시코드를 반환합니다.
    • 기본 구현 코드:
      public String toString() {
          return getClass().getName() + "@" + Integer.toHexString(hashCode());
      }
      
    • 출력 예:
      Object obj = new Object();
      System.out.println(obj.toString());
      // 출력: java.lang.Object@1a2b3c4d (클래스 이름 + @ + 해시코드)
      

2. toString() 메서드의 역할

  1. 객체의 문자열 표현 제공:
    • 객체를 문자열로 변환하여 출력하거나 로그에 기록할 때 사용됩니다.
  2. 디버깅과 로깅에 유용:
    • 객체의 상태를 문자열로 표현하여 디버깅 시 유용한 정보를 제공할 수 있습니다.
  3. 사용자 정의 출력:
    • 객체의 내용을 사용자 정의 형식으로 출력할 수 있도록 오버라이딩하여 활용할 수 있습니다.

3. toString() 메서드 오버라이드

오버라이드 필요성

  • 기본 toString() 메서드는 클래스 이름과 해시코드만 반환하므로, 객체의 상태를 의미 있게 표현하려면 오버라이드가 필요합니다.

오버라이드 예제

class Person {
    private String name;
    private int age;

    // 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // toString() 오버라이드
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        System.out.println(person); // Person{name='Alice', age=30}
    }
}

4. 자동 호출

  • toString()은 자동으로 호출됩니다:
    • 객체를 System.out.println()으로 출력할 때.
    • 문자열 연결 연산(+)에서 객체가 포함될 때.

예제

Person person = new Person("Alice", 30);
System.out.println(person); // 자동으로 person.toString() 호출
System.out.println("Person info: " + person); // 자동으로 호출

5. toString() 구현 시 고려사항

  1. 객체의 주요 정보를 포함:
    • 클래스의 중요한 필드 값(상태)을 문자열에 포함하여 의미 있게 출력되도록 해야 합니다.
  2. 간결한 형식 유지:
    • 너무 길거나 복잡하지 않도록 간결하게 작성합니다.
  3. 유용성:
    • 디버깅과 로깅에 유용하도록 객체의 상태를 쉽게 파악할 수 있게 작성합니다.

6. IDE를 활용한 toString() 자동 생성

많은 IDE(예: IntelliJ IDEA, Eclipse)에서는 클래스의 toString() 메서드를 자동으로 생성할 수 있는 기능을 제공합니다.

IntelliJ IDEA에서 자동 생성

  1. 클래스 내부에서 마우스 우클릭 → GeneratetoString() 선택.
  2. 포함할 필드 선택 → 자동 생성.

자동 생성 예제

@Override
public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

7. toString() 메서드와 주요 클래스

1) 기본 타입 래퍼 클래스 (Integer, Double 등)

  • toString() 메서드가 오버라이드되어, 객체 값을 문자열로 반환합니다.
Integer num = 100;
System.out.println(num.toString()); // "100"

2) String 클래스

  • String 클래스의 toString() 메서드는 객체 자체를 반환합니다.
String text = "Hello";
System.out.println(text.toString()); // "Hello"

3) 컬렉션 클래스

  • List, Set, Map 등의 컬렉션 클래스는 toString()을 오버라이드하여 요소들의 문자열 표현을 반환합니다.
List<String> list = Arrays.asList("A", "B", "C");
System.out.println(list.toString()); // [A, B, C]

8. toString() 활용 사례

1) 디버깅

  • 객체의 상태를 쉽게 확인할 수 있어 디버깅 시 유용합니다.
Person person = new Person("Alice", 30);
System.out.println(person); // Person{name='Alice', age=30}

2) 로깅

  • 로그 파일에 객체 상태를 기록할 때 사용됩니다.
logger.info("Current User: " + user);

3) JSON 형식 출력

  • 객체의 상태를 JSON 형태로 표현하여 API 응답에 활용할 수도 있습니다.
@Override
public String toString() {
    return "{ \"name\": \"" + name + "\", \"age\": " + age + " }";
}

9. toString()와 다른 메서드 비교

hashCode()

  • hashCode()는 객체를 식별하는 고유한 정수 값을 반환합니다.
  • toString()과 달리 객체의 문자열 표현이 아니라, 해시 값을 제공합니다.

equals()

  • equals()는 객체의 동등성을 비교하는 메서드로, toString()과는 기능적으로 다릅니다.

10. 결론

  • toString()은 객체를 문자열로 표현하기 위한 메서드로, 모든 클래스에서 활용 가능한 유용한 도구입니다.
  • 기본 구현은 클래스 이름과 해시코드를 반환하지만, 의미 있는 정보 제공을 위해 오버라이드하는 것이 일반적입니다.
  • 디버깅, 로깅, 출력 등에서 객체 상태를 확인하는 데 필수적인 메서드로, 실무에서도 자주 사용됩니다.

아래는 제네릭에서 toString()을 재정의하여 System.out.println()으로 결과를 출력하는 간단한 예시 5가지입니다. 제네릭 클래스를 활용하여 다양한 타입을 처리하면서 toString() 메서드를 이용한 출력 결과를 확인할 수 있습니다.


1. 문자열(String) 처리

class GenericPrinter<T> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    @Override
    public String toString() {
        return "Material: " + material.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        GenericPrinter<String> printer = new GenericPrinter<>();
        printer.setMaterial("Hello, World!");
        System.out.println(printer); // 출력: Material: Hello, World!
    }
}

2. 숫자(Integer) 처리

class GenericPrinter<T> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    @Override
    public String toString() {
        return "Number: " + material.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        GenericPrinter<Integer> printer = new GenericPrinter<>();
        printer.setMaterial(42);
        System.out.println(printer); // 출력: Number: 42
    }
}

3. 사용자 정의 객체 처리

class Powder {
    @Override
    public String toString() {
        return "재료는 Powder입니다";
    }
}

class GenericPrinter<T> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    @Override
    public String toString() {
        return material.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        GenericPrinter<Powder> printer = new GenericPrinter<>();
        printer.setMaterial(new Powder());
        System.out.println(printer); // 출력: 재료는 Powder입니다
    }
}

4. 다중 제네릭 활용

class GenericPrinter<T, U> {
    private T material;
    private U quantity;

    public void set(T material, U quantity) {
        this.material = material;
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return "Material: " + material.toString() + ", Quantity: " + quantity.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        GenericPrinter<String, Integer> printer = new GenericPrinter<>();
        printer.set("Powder", 5);
        System.out.println(printer); // 출력: Material: Powder, Quantity: 5
    }
}

5. 다양한 타입의 제네릭 처리

class GenericPrinter<T> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    @Override
    public String toString() {
        return "Type: " + material.getClass().getSimpleName() + ", Value: " + material.toString();
    }
}

public class Main {
    public static void main(String[] args) {
        // String 타입
        GenericPrinter<String> stringPrinter = new GenericPrinter<>();
        stringPrinter.setMaterial("Hello");
        System.out.println(stringPrinter); // 출력: Type: String, Value: Hello

        // Integer 타입
        GenericPrinter<Integer> intPrinter = new GenericPrinter<>();
        intPrinter.setMaterial(123);
        System.out.println(intPrinter); // 출력: Type: Integer, Value: 123

        // Double 타입
        GenericPrinter<Double> doublePrinter = new GenericPrinter<>();
        doublePrinter.setMaterial(45.67);
        System.out.println(doublePrinter); // 출력: Type: Double, Value: 45.67
    }
}

결론

  • System.out.println()은 항상 객체의 toString()을 호출하므로, 객체의 정보를 직관적으로 나타내려면 toString() 재정의는 필수입니다.
  • 제네릭은 다양한 타입을 처리할 수 있도록 설계되어, 유연하고 타입 안정성을 유지하며 동작합니다.

0개의 댓글