Object.toString() 는 객체의 정보를 문자열로 저장한다.
우선 어떤 결과를 보여주는지 1차적인 코드를 남겨둔다.
public class ToStringMain1 {
public static void main(String[] args) {
Object object = new Object(); //Object의 생성자 / toString을 호출하려면 생성자가 필요하다.
String string = object.toString(); // String 타입에 string에 object.toString()을 담았다.
//toString의 반환값을 출력
System.out.println(string); //toString을 활용해서 출력한 데이터인것이다.
//object를 직접 출력
System.out.println(object); //toString 없이 println을 통해서 출력한 것이다.
}
}

첫줄은 toString을 통해서 출력된 작업결과로 "(메서드명.참조주소-16진수)"로 출력해준다.
그런데... 둘째줄은 toString을 거치지 않은 결과물이지만, 결과가 똑같다.
"Println"의 내부적인 절차는
public void println(Object obj) {
String str = String.valueOf(obj); // 👈 여기서 obj.toString() 호출됨
...
}
요렇게 되어있고 , 추가적으로 String.valueIf(obj) 의 내부절차는
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
요래 되어있어서 결과적으로 "toString()"을 거치기 때문이라고 한다.
그래서 우선 Car라는 클래스를 생성하고
public class Car {
private String carName;
public Car(String carName){
this.carName = carName;
}
}
public class ToStringMain {
public static void main(String[] args) {
Car car = new Car("model Y"); //Car 객체 생성, 부모클래스인 toString사용도 가능하다.
System.out.println("1. 단순 toString 호출");
System.out.println(car.toString()); //car.toString으로 출력했지만,
//Object클래스의 toString 을 사용한 결과이다.
System.out.println("2. println 내부에서 toString 호출");
System.out.println(car); // toString 을 거치지 않았지만, print문의 특성에 따라 toString이 발동되었다.
}
}
실행해보면 결과는 아래와 같다.

이것만 역시 결과는 같다.
그럼 결과를 추가적으로 보기위해서 ... Dog 클래스를 만들었다.
public class Dog {
private String dogName;
private int age;
//Dog의 생성자 이름과 나이를 받아 저장한다.
public Dog(String dogName, int age) {
this.dogName = dogName;
this.age = age;
}
//Object클래스의 toString메서드를 오버라이딩 했다. (재정의)
@Override
public String toString(){
return "dogName=" + dogName + "/" + "age=" + age;
}
}
그리고 toString을 재정의 했다.
public class ToStringMain {
public static void main(String[] args) {
Car car = new Car("model Y"); //Car의 생성자
Dog dog = new Dog("멍뭉이",2); //Dog의 생성자
System.out.println("1. 단순 toString 호출");
System.out.println(car.toString());
System.out.println(dog.toString());
System.out.println("2. println 내부에서 toString 호출");
System.out.println(car);
System.out.println(dog);
}
}
이에 따르는 결과는

첫번째 Car의 결과는 toString 의 구조대로, 클래서정보@16진수참조주소값이 정상출력되었고
두번째 Dog의 결과가 주소값이 아닌 우리가 흔하게 보는 "값" 이 출력되었다.
오버라이딩(재정의) 했을 뿐인데 이렇게 출력되는 무언가가 있는가?
Chat GPT
🔥 그 이유는 "동적 바인딩(Dynamic Dispatch)" 덕분이야즉, toString()처럼 오버라이딩 가능한 메서드는"실제 객체 타입" 기준으로 호출된다. JVM은 Object의 toString()이 오버라이딩되어 있다면, 실제 객체의 toString()을 호출함(이걸 "다형성(Polymorphism)" + "동적 바인딩" 이라고 부름) |
그래서 동적 바인딩이 뭔데...

"다이나믹 디스패치(Dynamic Dispatch)는 그냥 JVM 내부에서 자동으로 처리되는 건가?
내가 직접 볼 수 있는 코드나 명시적인 규칙은 없나?"
👉 결론은 YES, 정확해.
다이나믹 디스패치는 JVM의 내부 설계에 의한 동작이지,
개발자가 직접 dynamicDispatch() 같은 코드를 호출하는 방식은 아니야.
✅ 정리: 다이나믹 디스패치는 "보이지 않지만 존재하는 룰"
그냥 외우는게 맞다고한다...
즉 결과적으로, 다형성으로 인한 Overriding + toString의 결과는 "주소가 아닌 값"을 그대로 출력해준다고한다.
정리하면
Dog(sub클래스) 의 생성자를 통해서 Object(super클래스)내부의 "toString"을 호출하면
참조주소를 뱉어내야 하지만!!
이때 JVM이 혹시~!~ sub클래스에 오버라이딩된 "내이름(toString) 이 있나?" 라고 쭉 훓어보고 1순위로 오버라이딩 된 결과를 출력해 버린다고 한다. (요게 다형성 + 오버라이딩)
그러면 다이나믹 디스패치(동적바인딩)가 발동되면서! 값을 보여주는 마법이라고...

'Java_library > Object 클래스' 카테고리의 다른 글
| (Java_library) Object.equals() (0) | 2025.05.01 |
|---|---|
| Object 클래스 - 최상위 클래스 (0) | 2025.05.01 |