ch7_상속
통합 문서입니다.
1. 상속과 다형성
상속과 다형성
학습 목표
- 상속이 필요한 상황과 피해야 할 상황을 구분할 수 있다.
- 오버라이딩 규칙과 동적 바인딩을 이해해 다형성 코드를 설계할 수 있다.
- 추상 클래스/조합(composition)의 선택 기준을 설명할 수 있다.
1. 상속이란 무엇인가
상속은 기존 클래스의 상태/행위를 재사용해 새로운 클래스를 정의하는 방법이다.
class Animal { ... }
class Dog extends Animal { ... }
적절한 관계:
Dog is-a Animal처럼 의미적으로 포함 관계가 성립할 때
부적절한 관계:
- 단순 코드 재사용만 목적일 때 (
has-a인데is-a로 억지 설계)
2. 상속의 장점과 비용
장점:
- 공통 코드 재사용
- 상위 타입 추상화
- 다형성 기반 확장성
비용:
- 부모-자식 강결합
- 부모 변경이 자식에 파급
- 깊은 계층에서 이해/디버깅 어려움
3. 오버라이딩(Overriding)
자식 클래스가 부모 메소드를 재정의하는 기능이다.
class Animal {
void sound() { System.out.println("..."); }
}
class Dog extends Animal {
@Override
void sound() { System.out.println("멍멍"); }
}
규칙:
- 메소드 시그니처 동일
- 접근 제어는 더 좁힐 수 없음
- 반환 타입은 공변 반환 허용 범위 내
@Override를 반드시 붙여 컴파일 타임 검증 권장
4. 다형성과 동적 바인딩
Animal a = new Dog();
a.sound(); // Dog.sound()
컴파일 시 타입은 Animal, 실행 시 실제 객체는 Dog이므로
호출 메소드는 런타임에 결정된다(동적 디스패치).
다형성 장점:
- 호출 코드를 바꾸지 않고 구현체를 교체 가능
- OCP(개방-폐쇄 원칙)에 유리
5. 업캐스팅/다운캐스팅
5.1 업캐스팅
Animal a = new Dog(); // 자동
자식을 부모로 다루는 것은 안전해 자동 변환된다.
5.2 다운캐스팅
Animal a = new Dog();
Dog d = (Dog) a; // 명시적
실제 객체 타입이 다르면 ClassCastException 발생.
필요 시 instanceof로 안전성 점검.
6. super의 역할
super는 부모 멤버/생성자 접근에 사용한다.
class Dog extends Animal {
Dog(String name) {
super(name); // 부모 생성자 호출
}
}
부모 생성자 호출은 자식 생성자 첫 줄에서 수행되어야 한다.
7. 추상 클래스(Abstract Class)
추상 클래스는 공통 구현 + 강제 규약을 함께 제공할 수 있다.
abstract class Shape {
abstract double area();
void print() { System.out.println("shape"); }
}
특징:
- 직접 인스턴스 생성 불가
- 일부 메소드는 구현, 일부는 추상으로 강제 가능
8. 상속 vs 조합(Composition)
조합은 “다른 객체를 필드로 포함”해 기능을 조립하는 방식이다.
class Car {
private Engine engine;
}
선택 기준:
- is-a 관계가 명확: 상속
- 기능 조립/유연 교체가 중요: 조합
실무에서는 조합이 더 유연한 경우가 많다.
9. 다형성 설계 패턴 예시
- 결제 수단별 처리
- 알림 채널(Email/SMS/Push)
- 파일 저장 전략(Local/S3)
공통 상위 타입(추상클래스/인터페이스)으로 의존하면
구현체 추가 시 기존 코드 수정이 최소화된다.
10. 실무에서 자주 하는 실수
- 상속 계층이 너무 깊어짐
- 부모 클래스에 과도한 책임 집중
- 다운캐스팅 남용
- 오버라이딩 없이 복붙으로 메소드 중복
- 단순 재사용 목적으로 잘못된 상속 관계 도입
11. 정리
- 상속은 강력하지만 결합이 큰 도구다.
- 다형성은 확장성을 높이는 핵심 메커니즘이다.
- “상속이 기본, 조합이 예외”가 아니라 상황에 따라 신중히 선택해야 한다.
2. 문제
문제
ch7 범위(상속/오버라이딩/다형성/추상클래스) 문제입니다.
A. 상속 기초
Animal부모 클래스와Dog,Cat자식 클래스를 작성하시오.name,age공통 필드는 부모에 두고 자식에서 재사용하시오.- 각 자식 클래스에 고유 메소드를 추가하시오.
super(...)를 사용해 부모 생성자를 호출하시오.
B. 오버라이딩
sound()메소드를 자식별로 오버라이딩하시오.@Override를 제거했을 때 발생할 수 있는 문제를 설명하시오.- 접근제어를 잘못 좁힐 때 컴파일 오류를 재현하시오.
- 부모 메소드와 자식 메소드를 모두 호출하는 코드를 작성하시오(
super.sound()).
C. 다형성
Animal[]배열에Dog,Cat,Bird를 담고 반복 호출하시오.- 업캐스팅된 참조에서 공통 메소드만 호출 가능한 이유를 설명하시오.
instanceof를 사용해 안전한 다운캐스팅을 구현하시오.- 잘못된 다운캐스팅으로
ClassCastException을 재현하고 수정하시오.
D. 추상 클래스
Shape추상 클래스를 만들고area()추상 메소드를 선언하시오.Circle,Rectangle자식 클래스를 구현하시오.Shape타입 컬렉션으로 전체 넓이 합계를 계산하시오.- 추상 클래스에 공통 구현 메소드(
printInfo)를 추가하시오.
E. 설계 문제
- 결제 시스템을 상속 구조로 설계해보시오.
- 같은 요구사항을 조합(Composition) 구조로 다시 설계하시오.
- 두 설계의 장단점을 비교하시오.
F. 챌린지
- 게임 캐릭터 계층(
Character,Warrior,Mage)을 설계하고 스킬 오버라이딩을 구현하시오. final메소드/클래스를 적용해 확장을 제한해야 하는 케이스를 구현하시오.- 리스코프 치환 원칙(LSP)을 깨는 예시를 만들고 개선하시오.
제출 체크리스트
- 상속 관계가 진짜 is-a인지 검토했는가?
- 다운캐스팅은 최소화하고 안전검사를 했는가?
- 공통 코드는 부모로, 개별 동작은 자식으로 분리했는가?
- 상속 대신 조합이 더 나은 지점을 판단했는가?