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

+ Recent posts