다형성(Polymorphism)이란?
다형성은 객체 지향 프로그래밍(OOP)에서 가장 핵심적인 개념 중 하나입니다. 이름 그대로 하나의 작업을 여러 가지 형태로 수행할 수 있게 해주는 기능으로, 동일한 메서드 호출이라도 상황에 따라 서로 다른 동작을 하도록 만들 수 있습니다.
다형성은 구현 시점에 따라 크게 두 가지로 나뉩니다.
- 컴파일 타임 다형성(Compile-time Polymorphism): 메서드 오버로딩(Method Overloading)이 대표적인 예입니다.
- 런타임 다형성(Runtime Polymorphism): 메서드 오버라이딩(Method Overriding)이 대표적인 예입니다.
두 다형성의 주요 차이점 비교
| 번호 | 구분 | 컴파일 타임 다형성 | 런타임 다형성 |
|---|---|---|---|
| 1 | 기본 개념 | 메서드와 객체 간의 바인딩(binding)이 컴파일 시점에 이루어집니다. | 어떤 메서드가 호출될지 실행(런타임) 시점에 결정됩니다. |
| 2 | 바인딩 방식 | 정적 바인딩(static binding)을 통해 구현됩니다. | 동적 바인딩(dynamic binding)을 통해 구현됩니다. |
| 3 | 상속 여부 | 상속이 필요하지 않습니다. | 클래스 간 상속 관계가 반드시 필요합니다. |
| 4 | 대표 예시 | 메서드 오버로딩 | 메서드 오버라이딩 |
컴파일 타임 다형성 예제 (메서드 오버로딩)
public class Main {
public static void main(String args[]) {
CompileTimePolymorphismExample obj = new CompileTimePolymorphismExample();
obj.display();
obj.display("Polymorphism");
}
}
class CompileTimePolymorphismExample {
void display() {
System.out.println("매개변수 없는 display 메서드 호출");
}
void display(String value) {
System.out.println("매개변수 있는 display 메서드 호출: " + value);
}
}위 예제처럼 같은 이름의 display() 메서드를 매개변수의 개수와 타입만 다르게 여러 번 정의하는 것이 오버로딩입니다. 컴파일러가 호출 시점에 전달된 인자를 보고 어떤 메서드를 실행할지 미리 결정하기 때문에 '컴파일 타임' 다형성이라고 부릅니다.
런타임 다형성 예제 (메서드 오버라이딩)
class ParentClassExample {
public void display() {
System.out.println("부모 클래스의 메서드 (오버라이딩된 메서드)");
}
}
class SubClassExample extends ParentClassExample {
@Override
public void display() {
System.out.println("자식 클래스의 메서드 (오버라이딩하는 메서드)");
}
}
public class Main {
public static void main(String args[]) {
ParentClassExample obj = new SubClassExample(); // 업캐스팅
obj.display(); // 자식 클래스의 메서드가 실행됨
}
}위 예제에서 참조 변수의 타입은 부모 클래스(ParentClassExample)이지만, 실제 생성된 객체는 자식 클래스(SubClassExample)입니다. JVM이 실행 시점에 실제 객체의 타입을 확인하여 자식 클래스에서 재정의한 display() 메서드를 호출하는데, 이것이 바로 동적 바인딩에 의한 런타임 다형성입니다.
정리
컴파일 타임 다형성은 오버로딩과 정적 바인딩으로, 런타임 다형성은 오버라이딩, 상속, 그리고 동적 바인딩으로 구현됩니다. 두 개념을 정확히 구분하면 객체 지향 설계에서 코드의 유연성과 확장성을 크게 높일 수 있습니다.