Polymorphism이란? Java의 ‘Shape‑Shifting’ 슈퍼파워

발행: (2026년 3월 5일 오후 12:06 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

스마트폰을 상상해 보세요. 그 하나의 장치는 카메라, GPS, 음악 플레이어, 그리고 웹 브라우저 역할을 합니다. 어떤 앱을 열느냐에 따라 화면과 버튼이 다르게 동작하지만, 여러분이 손에 들고 있는 물리적인 하드웨어는 동일합니다.

Java 프로그래밍에서 이 능력을 다형성이라고 합니다. 이 단어는 그리스어에서 유래했으며: poly (많음)와 morph (형태)입니다. 이는 하나의 동작이 작용하는 객체에 따라 다르게 동작하도록 하여, 기존 코드를 파괴하지 않고도 새로운 기능을 추가할 수 있는 유연하고 “미래‑지향적인” 소프트웨어를 가능하게 합니다.

Java에서의 다형성 유형

메서드 오버로드 (컴파일 시 다형성)

오버로드를 사용하면 같은 이름이지만 매개변수 목록이 다른 여러 메서드를 정의할 수 있습니다. 컴파일러는 제공된 인자를 기반으로 호출할 메서드 버전을 결정합니다.

class MathWizard {
    // Version 1: Multiplies two integers
    int multiply(int a, int b) {
        return a * b;
    }

    // Version 2: Multiplies three integers (Overloaded)
    int multiply(int a, int b, int c) {
        return a * b * c;
    }

    // Version 3: Multiplies doubles (Overloaded)
    double multiply(double a, double b) {
        return a * b;
    }
}

public class OverloadDemo {
    public static void main(String[] args) {
        MathWizard wizard = new MathWizard();

        // Java knows exactly which method to call based on the arguments
        System.out.println(wizard.multiply(5, 4));       // Calls Version 1
        System.out.println(wizard.multiply(5.5, 2.0));   // Calls Version 3
    }
}

메서드 오버라이딩 (런타임 다형성)

오버라이딩은 서브클래스가 슈퍼클래스에 이미 정의된 메서드에 대해 자체 구현을 제공할 때 발생합니다. 어떤 메서드를 실행할지는 프로그램이 실행되는 동안 결정됩니다.

// Parent class
class ElectronicDevice {
    void turnOn() {
        System.out.println("Device is powering up...");
    }
}

// Child class 1
class Television extends ElectronicDevice {
    @Override
    void turnOn() {
        System.out.println("TV showing: Welcome Screen.");
    }
}

// Child class 2
class SoundSystem extends ElectronicDevice {
    @Override
    void turnOn() {
        System.out.println("SoundSystem: Initializing Surround Sound.");
    }
}

public class RemoteApp {
    public static void main(String[] args) {
        // Polymorphic array: one type (ElectronicDevice) holding many forms
        ElectronicDevice[] livingRoom = { new Television(), new SoundSystem() };

        for (ElectronicDevice device : livingRoom) {
            // This is polymorphism in action!
            // The 'turnOn' behavior changes based on the actual object type.
            device.turnOn();
        }
    }
}

실제 API 예시

curl -X POST http://localhost:8080/api/home/activate \
     -H "Content-Type: application/json" \
     -d '{"action": "power_on"}'

응답

{
  "status": "Success",
  "devices_activated": [
    "TV Screen Active",
    "Audio Surround Initialized"
  ],
  "message": "Polymorphism handled the routing to correct device logic."
}

다형성의 장점

  • Flexibility – 런타임까지 구체적인 서브클래스(Circle, Square 등)를 알 필요 없이 일반 타입(예: Shape)으로 동작하는 코드를 작성합니다.
  • Clean Code – 객체 타입을 검사하는 긴 if‑else 또는 switch 문을 없앱니다.
  • Extensibility – 기본 타입을 처리하는 코드를 수정하지 않고 새로운 서브클래스(예: Triangle)를 추가합니다.

Source:

모범 사례

  • @Override 사용 – 항상 오버라이드하는 메서드에 주석을 달아 주세요. 철자 오류를 잡아주고 실제로 슈퍼클래스의 메서드를 오버라이드하고 있는지 확인할 수 있습니다.
  • 리스코프 치환 원칙 – 서브클래스는 슈퍼클래스를 대체할 수 있어야 하며, 이를 통해 프로그램이 깨지지 않아야 합니다.
  • 인터페이스 선호 – 현대 Java에서는 깊은 클래스 계층 구조보다 인터페이스를 사용해 다형성을 보다 깔끔하게 구현하는 경우가 많습니다.
  • 형 변환 피하기instanceof와 캐스팅(예: (Television) device)을 자주 사용한다면 다형성을 충분히 활용하고 있지 않은 것입니다. 오버라이드된 메서드가 동작을 처리하도록 하세요.

결론

Java의 다형성은 코드를 우아하고 확장 가능하게 만들어 줍니다. 공통 인터페이스나 슈퍼클래스를 통해 서로 다른 객체를 다룸으로써 복잡성을 줄이고 애플리케이션을 더 쉽게 유지 관리할 수 있습니다. 이는 경직된 코드와 유연하고 유기적인 소프트웨어 설계 사이의 간극을 메워 줍니다.

추가 읽을거리

0 조회
Back to Blog

관련 글

더 보기 »

실제로 이해가 되는 Java 배열 메서드

Arrays는 솔직히 처음에 혼란스러웠다. 개념 자체는 — 여러 값을 저장한다는 것, 괜찮다. 하지만 서로 다른 클래스에 흩어져 있는 모든 utility methods? 그게 …

단순함 때문에 승진하는 사람은 없다

“Simplicity는 위대한 미덕이지만, 이를 달성하려면 노력과 교육이 필요합니다. 그리고 상황을 더 악화시키는 것은 Complexity가 더 잘 팔린다는 점입니다.” — Edsger