본문으로 건너뛰기

7.1 OOP II — 상속과 다형성 개요 (Inheritance & Polymorphism Overview)

안내: 이 가이드는 Java 21 버전을 기준으로 작성되었습니다.

지금까지 클래스, 객체, 메서드, 생성자, 오버로딩 등 자바 OOP의 기초를 배웠습니다. 이번 챕터에서는 객체지향 프로그래밍의 진수인 상속(Inheritance), 다형성(Polymorphism), 추상화(Abstraction), 캡슐화(Encapsulation) 를 깊이 있게 다룹니다.

1. OOP II 주제 개요​

주제키워드핵심 개념
상속extends부모 클래스의 속성/기능을 물려받아 재사용
다형성@Override, 업/다운캐스팅하나의 코드로 다양한 타입 처리
추상화abstract, interface공통 기능만 정의하고 구현을 자식에게 위임
캡슐화private, getter/setter데이터를 숨기고 안전한 접근 경로 제공

2. 상속(Inheritance) 소개​

상속은 기존 클래스(부모/슈퍼 클래스)의 속성(필드)과 기능(메서드)을 새로운 클래스(자식/서브 클래스)가 물려받는 메커니즘입니다.

extends 키워드​

// 부모 클래스
public class Animal {
String name;
int age;

void eat() {
System.out.println(name + "이(가) 먹이를 먹습니다.");
}

void sleep() {
System.out.println(name + "이(가) 잠을 잡니다.");
}
}

// 자식 클래스: Animal을 상속
public class Dog extends Animal {
String breed; // 자식만의 추가 필드

void bark() { // 자식만의 추가 메서드
System.out.println(name + "이(가) 멍멍! 짖습니다.");
}
}

상속의 장점​

  1. 코드 재사용: 부모 클래스의 코드를 그대로 활용하므로 중복 작성 불필요
  2. IS-A 관계: "강아지는 동물이다(Dog IS-A Animal)" — 논리적으로 맞는 관계
  3. 유지보수: 부모 클래스를 수정하면 자식들에게 자동 반영
  4. 확장성: 기존 코드 변경 없이 새로운 기능 추가 가능
public class InheritanceTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "바둑이"; // 부모에서 상속받은 필드
dog.age = 3; // 부모에서 상속받은 필드
dog.breed = "진돗개"; // 자식 고유 필드

dog.eat(); // 부모에서 상속받은 메서드: 바둑이이(가) 먹이를 먹습니다.
dog.sleep(); // 부모에서 상속받은 메서드: 바둑이이(가) 잠을 잡니다.
dog.bark(); // 자식 고유 메서드: 바둑이이(가) 멍멍! 짖습니다.
}
}

3. 상속 계층과 Object 클래스​

자바의 모든 클래스는 암묵적으로 java.lang.Object 클래스를 최상위 조상으로 가집니다.

Object
└── Animal
├── Dog
│ ├── Poodle
│ └── Husky
├── Cat
└── Bird
├── Parrot
└── Eagle
// 명시적으로 쓰지 않아도 Object를 상속
class Animal extends Object { ... } // 사실 이런 의미

// Object의 주요 메서드: 모든 클래스가 상속받음
Object obj = new Dog();
obj.toString(); // 객체 문자열 표현
obj.equals(obj); // 객체 동등성 비교
obj.hashCode(); // 해시 코드 반환
obj.getClass(); // 런타임 클래스 정보

4. 단일 상속만 가능한 이유 — 다이아몬드 문제​

자바는 클래스의 다중 상속을 허용하지 않습니다. 한 클래스는 오직 하나의 부모 클래스만 extends할 수 있습니다.

// 불가! 자바는 다중 상속 금지
// class SmartPhone extends Phone, Camera { } // 컴파일 에러

// 가능: 단일 상속
class SmartPhone extends Phone { ... }

다이아몬드 문제 (Diamond Problem)​

    Animal
/ \
Dog Cat
\ /
DogCat? ← 다이아몬드 문제!

만약 Dog와 Cat 모두 Animal의 sound() 메서드를 다르게 오버라이딩했을 때, DogCat이 sound()를 호출하면 어느 버전이 실행될지 모호합니다. 이 문제를 방지하기 위해 자바는 다중 상속을 금지합니다.

5. 인터페이스로 다중 구현 가능​

다중 상속의 대안으로, 자바는 인터페이스(Interface) 를 통해 다중 구현을 허용합니다.

interface Flyable {
void fly();
}

interface Swimmable {
void swim();
}

interface Runnable {
void run();
}

// 클래스는 여러 인터페이스를 구현 가능
class Duck extends Animal implements Flyable, Swimmable, Runnable {
@Override
public void fly() { System.out.println("오리가 날아갑니다!"); }

@Override
public void swim() { System.out.println("오리가 헤엄칩니다!"); }

@Override
public void run() { System.out.println("오리가 달립니다!"); }
}

6. 실전 예제: 동물 계층 구조​

// 최상위 부모: 모든 동물의 공통 속성과 행동
public class Animal {
protected String name;
protected String sound;
protected int legs;

public Animal(String name, String sound, int legs) {
this.name = name;
this.sound = sound;
this.legs = legs;
}

public void makeSound() {
System.out.println(name + ": " + sound);
}

public void move() {
System.out.println(name + "이(가) " + legs + "개의 다리로 이동합니다.");
}

public void introduce() {
System.out.printf("저는 %s입니다. 다리가 %d개이고 '%s' 소리를 냅니다.%n",
name, legs, sound);
}
}

// 자식 1: 강아지
public class Dog extends Animal {
private String breed;

public Dog(String name, String breed) {
super(name, "멍멍", 4); // 부모 생성자 호출
this.breed = breed;
}

public void fetch() {
System.out.println(name + "이(가) 공을 가져옵니다!");
}

@Override
public void introduce() {
super.introduce();
System.out.println("품종: " + breed);
}
}

// 자식 2: 고양이
public class Cat extends Animal {
private boolean isIndoor;

public Cat(String name, boolean isIndoor) {
super(name, "야옹", 4);
this.isIndoor = isIndoor;
}

public void purr() {
System.out.println(name + "이(가) 그르릉~");
}

@Override
public void introduce() {
super.introduce();
System.out.println("실내 고양이: " + (isIndoor ? "예" : "아니오"));
}
}

// 자식 3: 새
public class Bird extends Animal {
private double wingspan;

public Bird(String name, double wingspan) {
super(name, "짹짹", 2);
this.wingspan = wingspan;
}

public void fly() {
System.out.printf("%s이(가) 날개 %.1fcm로 날아갑니다!%n", name, wingspan);
}
}

// 실행 테스트
public class AnimalTest {
public static void main(String[] args) {
Animal[] animals = {
new Dog("바둑이", "진돗개"),
new Cat("나비", true),
new Bird("참새", 20.5)
};

System.out.println("=== 동물 소개 ===");
for (Animal a : animals) {
a.introduce(); // 다형성: 각 타입의 introduce() 호출
a.makeSound(); // 다형성: 각 타입의 소리
System.out.println("---");
}

// 자식 고유 메서드는 다운캐스팅 필요
Dog dog = (Dog) animals[0];
dog.fetch();

Cat cat = (Cat) animals[1];
cat.purr();

Bird bird = (Bird) animals[2];
bird.fly();
}
}

출력:

=== 동물 소개 ===
저는 바둑이입니다. 다리가 4개이고 '멍멍' 소리를 냅니다.
품종: 진돗개
바둑이: 멍멍
---
저는 나비입니다. 다리가 4개이고 '야옹' 소리를 냅니다.
실내 고양이: 예
나비: 야옹
---
저는 참새입니다. 다리가 2개이고 '짹짹' 소리를 냅니다.
참새: 짹짹
---
바둑이이(가) 공을 가져옵니다!
나비이(가) 그르릉~
참새이(가) 날개 20.5cm로 날아갑니다!

7. 챕터 7에서 배울 내용 미리보기​

섹션주제핵심 내용
7.2 상속extends, super(), 메서드 오버라이딩부모-자식 관계, 생성자 체이닝
7.3 다형성업캐스팅, 다운캐스팅, instanceof유연한 코드 작성, 동적 바인딩
7.4 추상화abstract, interface설계 도구, 계약 기반 프로그래밍
7.5 캡슐화private, getter/setter, Record데이터 보호, 불변 클래스
7.6 supersuper.필드, super.메서드(), super()부모 멤버 접근, 생성자 연쇄
왜 이 개념들이 중요한가?

상속, 다형성, 추상화, 캡슐화는 단순한 문법이 아닙니다. 이 개념들은 디자인 패턴, SOLID 원칙, Spring Boot 프레임워크 등 현업에서 사용하는 모든 고급 기술의 기반이 됩니다. 이 챕터를 충분히 이해하면 프로급 자바 개발자로 도약하는 발판이 마련됩니다.

요약​

개념핵심
상속extends로 부모의 필드·메서드 재사용
Object 클래스모든 클래스의 최상위 조상
단일 상속다이아몬드 문제 방지, 클래스는 하나만 상속
다중 구현implements로 여러 인터페이스 구현 가능
IS-A 관계상속은 논리적 계층 구조를 반영해야 함