본문으로 건너뛰기

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? ← 다이아몬드 문제!

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

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 관계상속은 논리적 계층 구조를 반영해야 함