자바 다형성(Polymorphism) – 하나의 객체, 여러 타입
다형성(Polymorphism)은 하나의 객체가 부모·인터페이스·자식 등 여러 타입으로 참조될 수 있는 객체-지향 핵심 개념입니다.
덕분에 동일한 코드가 다양한 객체를 유연하게 처리하고, 런타임에 실제 타입에 맞춰 동적 바인딩이 이뤄집니다.
1. 참조 변수의 다형성
부모 타입 → 자식 객체 Upcasting
Parent p = new Child(); // 자동 형변환
- 부모 멤버만 사용 가능
- 오버라이딩된 메서드는 자식 버전이 실행
자식 타입 ← 부모 객체 Downcasting
Child c = (Child) p; // 명시적 형변환 + instanceof 체크
- 실제 객체가 해당 타입인지 검증 필수
- 잘못된 캐스팅 →
ClassCastException
2. instanceof로 타입 확인
if (obj instanceof Dog) {
Dog d = (Dog) obj;
d.bark();
}
null검사 불필요 –null instanceof는 언제나 false
3. 동적 메서드 바인딩
class Animal { void sound(){ … } }
class Dog extends Animal { @Override void sound(){ System.out.println("멍멍"); } }
Animal a = new Dog();
a.sound(); // 출력: 멍멍
참조 타입이 아닌, 실제 객체 타입에 따라 호출 메서드가 결정!
4. 다형성 활용 패턴
- 추상 클래스/인터페이스 배열로 여러 객체 일괄 처리
- 전략·템플릿 메서드 패턴 구현 시 타입 분기에 의존하지 않는 코드 작성
- 컬렉션에 부모 타입을 지정해 확장성 극대화
Animal[] animals = { new Dog(), new Cat() };
for (Animal ani : animals) ani.sound();
5. 상속·오버라이딩과의 관계
| 구분 | 상속 | 오버라이딩 | 다형성 |
|---|---|---|---|
| 핵심 역할 | 코드 재사용 | 동작 재정의 | 동적 호출·유연성 |
| 필요 조건 | 클래스 계층 | 부모 메서드 존재 | 상속 또는 인터페이스 구현 |
| 실행 시점 | 컴파일 | 런타임 | 런타임 |
6. 체크리스트 & 팁
- 공통 인터페이스부터 설계 – 다형성은 “공통 계약”이 핵심
instanceof남용 금지 – 가능하면 오버라이딩과 다형성 자체로 분기- 다운캐스팅 전 안전 검사 (
instanceof또는Optional) final·static메서드는 오버라이딩되지 않으므로 다형성 대상 아님
질문 정리
Q1. 다형성과 오버로딩 차이는?
오버로딩은 같은 클래스 안에서 메서드 시그니처만 다르게 정의, 다형성과 직결되지 않습니다.
Q2. 인터페이스만으로도 다형성이 가능한가요?
네. 인터페이스는 계약만 제시하므로 여러 구현 객체를 하나의 타입으로 다룰 수 있습니다.
Q3. 업캐스팅과 다운캐스팅 중 어느 쪽이 안전한가요?
업캐스팅(부모 타입 참조)은 항상 안전하지만, 다운캐스팅은 실제 타입 확인이 필수입니다.
Q4. 제네릭과 다형성은 어떻게 연결되나요?
제네릭은 컴파일-타임 타입 안정성을 제공하며, 런타임 다형성과 조합해 더 안전한 컬렉션 처리 가능.
Q5. 성능에 큰 영향이 있나요?
런타임 메서드 탐색 비용이 있지만 JIT 최적화 덕분에 대부분 무시할 수준입니다.
댓글남기기