7.3 다형성 (Polymorphism)
다형성(Polymorphism) 은 하나의 참조 변수로 여러 타입의 객체를 참조할 수 있는 객체지향의 가장 강력한 특징 중 하나입니다. 다형성 덕분에 코드가 유연해지고 변경에 강해집니다. 자바에서 다형성을 이해하려면 크게 두 가지 개념을 알아야 합니다.
- 메서드 오버라이딩 (Overriding): 부모의 메서드를 자식 입맛에 맞게 재정의하는 것
- 참조 변수의 형변환 (Upcasting / Downcasting): 부모 타입의 변수로 자식 객체를 가리키는 것
1. 메서드 오버라이딩 (Overriding)
앞서 상속에서는 부모의 메서드를 물려받아 그대로 쓴다고 했습니다. 그런데 물려받은 기능이 자식의 특성과 맞지 않다면 어떻게 할까요? 그럴 때는 물려받은 메서드의 내용을 자신에게 맞게 재정의 할 수 있습니다. 이를 오버라이딩이라고 합니다.
class Animal {
void cry() {
System.out.println("동물이 울음소리를 냅니다.");
}
}
class Dog extends Animal {
// 부모의 cry() 메서드를 재정의 (오버라이딩)
@Override
void cry() {
System.out.println("멍멍!");
}
}
class Cat extends Animal {
// 부모의 cry() 메서드를 재정의 (오버라이딩)
@Override
void cry() {
System.out.println("야옹~");
}
}
오버라이딩의 조건
- 메서드 이름, 매개변수, 반환 타입이 부모 클래스와 완전히 일치 해야 합니다.
- 부모 클래스의 메서드보다 접근 제어자를 더 좁은 범위로 변경할 수 없습니다. (예: 부모가
public인데 자식이private으로 덮어쓸 수 없음) @Override어노테이션을 붙여주면 컴파일러가 실수로 철자를 틀리지 않았는지 검사해 줍니다. (필수는 아니지만 강력히 권장)
2. 참조 변수의 형변환과 다형성의 진가
다형성의 진짜 마법은 부모 타입의 변수가 자식 타입의 객체를 참조할 때 나타납니다.
// 부모 리모컨(참조 변수)으로 자식 TV(객체)를 조종할 수 있다!
Animal myDog = new Dog(); // 조상 타입의 참조 변수로 자손 객체를 참조
Animal myCat = new Cat();
이 코드가 문제 없이 동작하는 이유는, Dog와 Cat 모두 Animal이기 때문입니다. ("강아지는 동물이다", "고양이는 동물이다" = 성립) 이를 업캐스팅(Upcasting) 이라고 하며, 생략이 가능합니다.
반대로 "동물은 강아지이다"는 항상 성립하지 않습니다. 그래서 부모 타입의 객체를 자식 변수에 담을 때는 명시적으로 괄호 (Type)를 적어주어야 합니다. 이를 다운캐스팅(Downcasting) 이라 부릅니다.
다형성을 활용한 유연한 코드
다형성이 왜 좋을까요? 여러 종류의 객체를 하나의 배열로 묶어서 다루거나 함수의 매개변수를 하나로 통일할 수 있기 때문입니다.
public class PolymorphismExample {
public static void main(String[] args) {
// 부모 타입 배열로 여러 자손 객체를 한 번에 관리
Animal[] animals = new Animal[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Animal();
// 반복문을 돌며 각각의 cry() 호출
for (Animal a : animals) {
a.cry(); // 객체의 실제 타입에 따라 다르게 울음 (동적 바인딩)
}
}
}
[실행 결과]
멍멍!
야옹~
동물이 울음소리를 냅니다.
부모 타입인 Animal 배열에 강아지와 고양이를 모두 넣었습니다! 그리고 a.cry()라는 동일한 명령 을 내렸지만, 실제로 가리키고 있는 객체가 Dog냐 Cat이냐에 따라 (자식 클래스에서 오버라이딩한 메서드가) 다르게 동작 합니다.
만약 부모 클래스와 다형성이 없었다면, Dog를 위한 배열과 반복문, Cat을 위한 배열과 반복문을 각각 따로따로 만들어야 했을 것입니다. 새로운 동물 Cow가 추가돼도 animals 배열에 넣기만 하면 기존 코드를 하나도 수정할 필요가 없습니다. 이것이 바로 객체지향의 강력한 무기, 다형성입니다!