JAVA

자바 다형성 — 하나의 타입으로 여러 객체를 다루기(POLYMORPHISM)

PANCO_IT
#자바#JAVA#다형성#오버라이딩#객체지향

같은 sound() 호출이 Dog·Cat·Bird에서 각각 다르게 동작하는 다형성 개념 그림

같은 명령(sound)을 내려도, 실제 객체가 무엇이냐에 따라 다르게 반응합니다.

지난 편에서 Dog, Cat이 모두 Animal을 상속받는 걸 봤습니다. 그렇다면 이 여럿을 하나로 묶어서 한꺼번에 다룰 수는 없을까요? "동물들아, 소리 내"라고 한 번에 명령하면 개는 멍멍, 고양이는 야옹 하도록요. 이걸 가능하게 하는 것이 객체지향의 꽃, 다형성입니다.

다형성이 뭔가요?

다형성(Polymorphism)은 같은 명령이 객체에 따라 다르게 동작하는 성질입니다. 부모 타입 하나로 여러 자식 객체를 가리킬 수 있고, 같은 메서드를 불러도 실제 객체에 맞는 동작이 나옵니다.

쉽게 — 리모컨의 '전원' 버튼 하나와 같습니다. 같은 버튼을 눌러도 TV는 화면을 켜고, 에어컨은 바람을 냅니다. 명령은 하나("전원 켜")인데, 대상에 따라 반응이 다르죠. 다형성도 이렇게 하나의 명령, 여러 반응입니다.

부모 타입에 자식을 담기

상속받은 자식은 부모 타입 변수에 담을 수 있습니다. "개는 동물이다"가 성립하니, Animal 타입에 Dog 객체를 넣어도 됩니다.

Animal a = new Dog();   // 부모 타입에 자식 객체를 담음

여기서 **선언 타입은 Animal, 실제 객체는 Dog**입니다. 이 둘이 다를 수 있다는 게 다형성의 출발점입니다.

다형성의 원리: 부모 타입으로 선언하고 자식 객체를 대입해 호출

그림 1. 선언은 부모(Animal), 실제 동작은 자식(Dog). 오버라이딩된 메서드가 실행됩니다.

같은 호출, 다른 동작

이제 핵심입니다. 부모 타입 변수로 메서드를 불러도, 실제 객체의 오버라이딩된 메서드가 실행됩니다.

class Animal {
    void sound() { System.out.println("동물이 소리를 냅니다."); }
}
class Dog extends Animal {
    @Override
    void sound() { System.out.println("멍멍!"); }
}

Animal a = new Dog();
a.sound();   // "멍멍!"  ← Animal 타입인데 Dog의 소리가 남

a의 타입은 Animal이지만, 안에 든 실제 객체가 Dog이라 Dogsound()가 실행됩니다. 7편의 오버라이딩이 여기서 빛을 발합니다.

왜 좋은가 — 여럿을 하나로 묶어 처리

다형성의 진짜 힘은 여러 종류를 하나의 타입으로 묶어 똑같이 다룰 때 나옵니다. Animal 배열에 개도 고양이도 담고, 반복문으로 한 번에 처리할 수 있습니다.

Animal[] animals = { new Dog(), new Cat(), new Animal() };
for (Animal a : animals) {
    a.sound();   // 각자 자기 소리를 냄
}
// 멍멍! / 야옹~ / 동물이 소리를 냅니다.

새로운 동물(Bird)이 생겨도 이 반복문은 한 글자도 안 고쳐도 됩니다. BirdAnimal을 상속해 sound()만 오버라이딩하면, 배열에 넣는 순간 알아서 짹짹 하고 웁니다. 이렇게 확장에 유연한 것이 다형성의 가장 큰 이점입니다.

단골 함정 — 부모 타입으론 자식 고유 기능을 못 부름

주의할 점이 하나 있습니다. Animal 타입 변수로는 Animal에 있는 기능만 부를 수 있습니다. Dog에만 있는 bark()는 부모 타입으로는 호출되지 않습니다.

Animal a = new Dog();
a.sound();   // OK: Animal에 있는 메서드
a.bark();    // 오류: Animal 타입에는 bark()가 없음

bark()를 쓰려면 다시 Dog 타입으로 형변환((Dog)a)해야 합니다. 선언 타입이 무엇을 쓸 수 있는지를 정한다고 기억하면 됩니다.

직접 실행해 보기

아래 코드를 돌려 보고, Bird 클래스를 만들어 배열에 추가해 보세요. 반복문은 그대로 두어도 새 소리가 납니다.

다형성 — 하나의 배열, 여러 소리
class Animal {
  void sound() { System.out.println("동물이 소리를 냅니다."); }
}
class Dog extends Animal {
  @Override
  void sound() { System.out.println("멍멍!"); }
}
class Cat extends Animal {
  @Override
  void sound() { System.out.println("야옹~"); }
}

public class Main {
  public static void main(String[] args) {
      Animal[] animals = { new Dog(), new Cat(), new Animal() };
      for (Animal a : animals) {
          a.sound();   // 같은 호출, 객체에 따라 다르게
      }
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

한 장 정리

용어
다형성같은 명령이 객체에 따라 다르게 동작하는 성질
부모 타입 참조Animal a = new Dog(); (선언은 부모, 실제는 자식)
동적 실행부모 타입으로 불러도 자식의 오버라이딩 메서드가 실행
묶어 처리Animal[]에 여러 자식을 담아 한 번에 다룸
함정부모 타입으론 자식 고유 메서드 호출 불가(형변환 필요)

이것만 기억하면 됩니다. 다형성은 부모 타입 하나로 여러 자식을 담고, 같은 메서드 호출이 실제 객체에 따라 다르게 동작하는 것입니다. 덕분에 여러 종류를 하나로 묶어 똑같이 다루고, 새 자식이 생겨도 기존 코드를 고치지 않아도 됩니다. 상속과 오버라이딩이 있어야 성립한다는 점도 함께 기억하세요.

미니 퀴즈

개념을 제대로 잡았는지 직접 풀어 봅니다. 정답은 눌러야 나옵니다.

미니 퀴즈

OX 2문제 + 4지선다 3문제


포켓코딩(JAVA2) 8편 · 예제 출처: 강사 개인 GitHub 저장소. 다음 편: (총정리) JAVA2 객체지향, 한 편으로 복습하기.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글