다형성은 어떻게 동작하는가?
다형성은 도대체 어떻게 동작하는 것일까요?
자식 객체를 부모 타입의 레퍼런스 변수에 대입하면, 어떻게 자식의 오버라이딩된 메서드가 호출되는 걸까요?
자바의 다형성을 설명하기 앞서 정적 바인딩에 대해 간략히 설명 드리겠습니다.
정적 바인딩 (Static Binding)
위 예시를 Java가 아니라, 정적 바인딩을 지원하는 가상의 언어라고 생각해봅시다.
정적 바인딩의 경우, 호출하는 함수의 주소가 컴파일 타임에 결정되기 때문에, 컴파일러가 함수의 호출문을 함수의 주소로 점프하는 기계어로 번역하게 됩니다. (어셈블리 코드 참조)
따라서 각 객체들은 함수의 주소를 저장할 필요 없이, 변수들만 저장하면 됩니다.
또한, 이미 결정된 주소로 가서 함수를 단순히 실행시키기만 하면 되기 때문에 오버헤드가 없고, 효율성이 높아집니다.
동적 바인딩 (Dynamic Binding)
다음으로, 동적 바인딩입니다.
동적 바인딩은 정적 바인딩과 달리 컴파일 타임에 바인딩이 이루어지는 것이 아니라, 런타임에 바인딩이 이루어지는 것을 말합니다.
위 예시에서는 Parent 클래스와 Child 클래스가 있습니다.
그리고, Child는 Parent를 상속받았습니다.
아래 1번 코드에서 Parent 타입의 레퍼런스 변수 p에는 Parent 객체가 들어가고,
2번에서 getName()을 호출하면 부모의 getName() 메서드가 호출됩니다.
반면, 3번에서는 Parent 타입의 레퍼런스 변수 c에 Child 객체를 대입합니다.
레퍼런스 변수 c는 이미지에서 빨간색으로 강조 표시해놓은 부분만, 즉, parent에 해당하는 부분만 접근할 수 있습니다.
하지만, 각 객체들은 함수의 위치를 나타내는 테이블을 가지고 있으며, 부모 클래스의 메서드를 오버라이딩한 자식 객체가 부모 타입의 레퍼런스 변수에 대입될 때, 테이블에서의 부모 객체의 메서드 주소가 자식 객체의 메서드 주소로 업데이트 됩니다.
이러한 메서드 호출과 실제 메서드의 바인딩이 런타임에 발생하고, 테이블을 업데이트하는 과정이 실행중에 발생하기 때문에 오버헤드가 발생합니다. 하지만, 다형성을 이용하여 더 유연한 프로그래밍이 가능하죠.
하지만, Java에서도 final, private, static 키워드를 사용하게 되면, 마찬가지로, 메서드의 주소를 컴파일 타임에 알 수 있기 때문에 정적 바인딩이 가능합니다.
참조
- PROGRAMMING LAGUAGE PRAGMATICS, 4th editio
'Java' 카테고리의 다른 글
Java 입출력, Scanner와 BufferedReader의 비교 (0) | 2022.07.25 |
---|---|
Java 입출력 (스트림, 버퍼) (0) | 2022.07.25 |
Java 8 / 11 / 17의 변화 (1) | 2022.07.04 |
JDBC란? (0) | 2020.07.11 |
JSTL(JSP Standard Tag Library)이란? (0) | 2020.07.09 |