오늘은 toString 메서드를 한번 알아 보도록 하자.
일단 toString을 알기전에 우리는 Object에 대해 알아야한다.
모든 클래스의 가장 최상위 클래스인 "Object" 클래스는 Java에 제공하는 모든 클래스들의 계층 구조로 되어있고, 그 최상위로 올라가면 "Object"이라는 클래스가 존재한다.
우리가 일반적으로 생성하는 클래스도 "extends"로 직접 상속하지는 않지만 자바 컴파일러는 일반 클래스를 "Object"하위 클래스로 자동 설정하게 되어있다.
즉, 자바 라이브러리나 유저가 만든 모든 클래스는 "Object" 클래스를 부모클래스로 상속 받아서 사용하게 된다.
toString 메서드는 모두 클래스 인스턴스의 데이터를 문자열로 반환하는 메서드이다.
이 메서드를 클래스에서 정의하는 것은 개발자 간의 약속이라고 할 수 있다.
원래 toString은 java.lang 패키지의 클래스에서 다음과 같이 정의된 메서드이며 "클래스 이름@해시값"의 형태로 문자열을 반환한다.
public class Object {
// 중략
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 중략
}
위에서도 말했지만 Java의 모든 클래스는 Object 클래스의 자식 클래스이다.(Object를 상속받는다.)
이때 toString 메서드를 다시 정의하면 'Object 클래스의 toString 메서드를 오버라이드했다.'라고 한다.
'오버라이드(Override)'는 상속받은 클래스가 부모의 메소드를 다시 정의하는 것이다.
당연한 말이지만 상속받은 클래스에서 toString 메서드를 다시 정의하지 않으면 부모인 Object 클래스의 toString을 그대로 상속받는다.
자바의 메서드를 오버라이드할 때는 클래스의 접근 제한을 바꿀 수 없다.
항상 public으로 정의해야 하는 것이다.
하지만 클래스에서 toString 메서드를 오버라이드할 때는 클래스의 특성이나 인스턴스의 상태를 나타내는 적절한 문자열을 반환하는 것이 좋다.
toString 메서드를 오버라이드하는 예제를 살펴보자.
package test;
// toString 메서드의 오버라이드 차이점 확인하기
class A {
// toString을 정의하지 않음
}
class B {
int x;
// 생성자
B(int x) { this.x = x; }
// toString을 오버라이드하기
public String toString() { return "B[" + x + "]"; }
}
public class ToStringTest {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
B b1 = new B(18);
B b2 = new B(55);
System.out.println("a1.toString() = " + a1.toString());
System.out.println("a2 = " + a2);
System.out.println("b1.toString() = " + b1.toString());
System.out.println("b2 = " + b2);
}
}
A 클래스는 toString 메서드를 오버라이드를 하지 않고 B 클래스는 toString 메서드를 오버라이드한 예제이다.
2개의 클래스(A, B)와 toString 메서드를 테스트하기 위한 클래스로, 클래스의 인스턴스를 각각 2개씩 생성한다.
다음은 위의 코드를 실행했을때의 예시이다.
1) a1.toString() = test.A@49e4cb85
2) a2 = test.A@22f71333
3) b1.toString() = B[18]
4) b2 = B[55]
1) "a1.toString() = test.A@49e4cb85" 을 출력한다.
이때 "49e4cb85"는 인스턴스 a1에 대해 Java가 임의로 부여한 해시값이다.
인스턴스에 대해 고유한 값이 생긴 것이라고 알아두면 될 것 같다.
앞의 "test.A" 는 클래스의 이름, 즉, test 패키지의 A 클래스를 의미한다.
2) a2를 그대로 출력한다.
그러면 자동으로 상속받은 Object 클래스의 toString 메서드를 호출한다.
왜냐하면 '문자열을 출력하는 함수에 클래스형 변수를 넣으면 자동으로 toString 메서드를 호출해라'
라는 규칙이 있기 때문이다.
따라서 "2 = test.A@22f71333" 를 출력한다.
3) B 클래스에서 다시 정의한 toString 메서드를 호출하기 때문에 "b1.toString() = B[18]" 를 출력한다.
4) 위와 마찬가지로 다시 정의한 toString 메서드를 호출하기 때문에 "b2 = B[55]" 를 출력한다.
toString 메서드에 대해 간단히 정리하면 다음과 같은 개발자 간의 약속과 규칙이 있음을 알 수 있다.
인스턴스의 상태를 간단한 문자열로 반환하는 메서드는 public String toString() 형식으로 정의하는 것이 좋다. 왜냐하면 인스턴스의 상태를 출력할 때 인스턴스를 출력하는 코드에 함께 넣으면 자동으로 호출되기 때문이다.