Java, Object - toString
Object 클래스의 toString() 메소드는 객체의 정보를 문자열로 반환하여 제공한다.
디버깅에 로깅에 유용하며 이 메소드는 Object 클래스에 정의되어 모든 클래스에서 상속 받아 사용할 수 있다.
ToStringMain.java
public class ToStringMain {
public static void main(String[] args) {
Object obj = new Object();
String str = obj.toString();
// object 출력
System.out.println(obj);
// toString() 반환값
System.out.println(str);
}
}
출력 결과
java.lang.Object@10f87f48
java.lang.Object@10f87f48
Object 타입 변수, String 타입 변수 모두 똑같은 값을 출력하고 있다.
toString()
toString() 메소드를 보기 위해 Object 내부 코드로 이동하도록 한다.
Object.java
- Object 클래스에서 toString() 메소드가 정의되어 있다.
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- getClass().getName() 패키지를 포함한 객체의 이름이다.
- java.lang.Object 출력하는 것을 볼 수 있는데 java.lang 패키지에서 Object 클래스가 있다는 의미이다.
- hashCode() 해시 값이 16bit 헥스 형태의 주소로 반환한다는 의미이다.
- 이 객체의 참조 주소 값을 알기 위한 용도이다.
toString() 메소드 용도는 사용하여 해당 객체의 패키지와 클래스명, 참조 값 알려준다.
println(obj), println(str) 결과 같은 이유
앞서 ToStringMain 함수에서 실행한 println(..), println(..) 결과가 똑같은 동작을 한 것을 볼 수 있었다.
// object 출력
System.out.println(obj); // obj 변수는 Object 타입
// toString() 반환값
System.out.println(str); // str 변수는 String 타입
왜 똑같은지 System.in.println() 메소드를 살펴볼 필요가 있다.
PrintStream.java
public void println(Object x) {
String s = String.valueOf(x);
// ...
print(s);
// ...
}
- Object 타입 객체가 온 경우, 오버로딩하여
println(Object x)
메소드를 호출한다. print(s)
화면에 문자열을 출력하는 코드로 보인다. 인자 값 s 변수는valueOf()
메소드를 사용하여 문자열을 반환한 것인데, 다시 파고들어 탐색한다.
String.java
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
여기서 Object 클래스의 toString() 메소드를 반환하여 문자열을 출력한 것을 볼 수 있다.
println() 오버로딩
다음으로 System.in.println() 메소드가 String 타입과 Object 타입을 받고 있다.
System.out.println(obj); // obj 변수는 Object 타입
System.out.println(str); // str 변수는 String 타입
- PrintStream.java 내부를 살펴보면, println 메소드가 여러 개 정의되어 있다.
타입에 따라 오버로딩하여 문자열을 출력하는 것이다.
즉, 앞서 만든 코드의 결과가 println(obj) , println(str) 동일한 역할의 로직을 수행하고 있다.
toString() 오버라이딩 재정의로 사용하기
Object.toString() 메소드는 클래스 정보와 참조 값을 제공하였다.
하지만 이러한 정보만으로 객체의 상태를 나타낼 수 없는데
자식 클래스에서 toString() 메소드를 오버라이딩하여 유용한 정보를 추가로 제공할 수 있다.
Cat.java
package object;
public class Cat {
private String name;
public Cat() {
name = "I am Cat";
}
public Cat(String name) {
this.name = name;
}
public void sound() {
System.out.println("cat sound");
}
}
Car.java
package object.toString;
public class Car {
public void move() {
System.out.println("car move");
}
}
ToStringMain.java
package object.toString;
public class ToStringMain {
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.toString());
Cat cat = new Cat("icefire");
System.out.println(cat.toString());
}
}
출력 결과
object.toString.Car@b4c966a
Cat Name: icefire
정적 메소드로 toString() 프린트하기
신규 클래스를 만들어 정적 메소드로 Object 인수를 받아 toString(); 정보를 출력하는 것이다.
ObjectPrint.java
package object.toString;
public class ObjectPrint {
public void getInfo(Object obj) {
String str = "(Debug) 객체 정보: " + obj.toString();
System.out.println(str);
}
}
ToStringMain.java
package object.toString;
public class ToStringMain {
public static void main(String[] args) {
Car car = new Car();
Cat cat = new Cat("icefire");
Object obj = new Object();
System.out.println("== 정적 메소드로 객체 정보출력하기 ==");
ObjectPrint.getInfo(car);
ObjectPrint.getInfo(cat);
ObjectPrint.getInfo(obj);
}
}
출력 결과
== 정적 메소드로 객체 정보출력하기 ==
(Debug) 객체 정보: object.toString.Car@4e50df2e
(Debug) 객체 정보: Cat Name: icefire
(Debug) 객체 정보: java.lang.Object@34a245ab
ObjectPrint 클래스의 getInfo 메소드로 Object 타입은 모든 참조를 할당할 수 있다. 이러한 특성은 다형적 참조이며 결과를 보듯이 모든 객체가 인자로 받아 정보를 출력한다.
그림으로 보기
Cat cat = new Cat();
ObjectPrint.getInfo(cat);
- Object obj 인수로 Cat 타입의 참조 값이 전달되었다.
- 메소드 내부에서는 obj.toString() 호출한다.
- 자신의 인스턴스 내부 Object 타입부터 toString() 찾는다
- Object 부터 살피는 이유는 obj 변수가 Object 타입이다.
- 찾아낸 toString() 메소드를 호출하지 않고,
자식 클래스에서 오버라이딩이 있는지 찾는다. - Cat 타입에서 toString() 메소드 오버라이딩이 있다.
- Cat.toString() 메소드를 호출한다.
Cat.toString() 호출 결과
(Debug) 객체 정보: Cat Name: icefire
toString() 참조 값을 출력하고 싶다면?
앞서 만든 코드에서 toString(), hashcode() 메소드를 재정의하면 참조 값을 출력하지 않는다는 것을 볼 수 있었다.
참조 값을 출력하는 방법은 toString() 소스 내부와 참고하여 작성하면 된다.
Cat cat = new Cat();
String ref = Integer.toHexString(System.identityHashCode(cat));
System.in.println("My Memory Reference Value: " + ref);
출력 결과
My Memory Reference Value: 7cc355be