[Java] Polymorphism

Jane·2021년 1월 15일
4
post-thumbnail

다형성 (Polymorphism)

다형성이란 프로그래밍 언어가 갖고 있는 자료형 체계의 성질을 설명하는 단어로, 프로그램 언어 각 요소(상수, 변수, 오브젝트, 메소드 등)이 다양한 자료형에 속하는 것이 허용되는 성질을 의미한다.

즉, 다형성이란 프로그램 언어의 각 요소가 '여러 가지 형태를 가질 수 있는 능력'이라고 이해할 수 있다.

🤔 그런데 여러가지 형태를 가진다는 게 무슨 뜻일까?

객체지향의 사실과 오해(일명 토끼책)에 따르면 다형성이란 서로 다른 유형의 객체가 동일한 메시지를 수신할 때 서로 다른 메서드를 이용해 메시지를 처리하는 것이다. 이런 관점에서 이해한다면 다형성은 하나의 메시지와 하나 이상의 메서드 사이의 관계이며, 하나의 객체는 동일한 역할을 수행할 수 있는 다른 객체로 대체할 수 있다는 것을 의미한다.

다형성의 장점

다형성의 장점은 객체들의 대체 가능성으로 인해 설계가 유연하고 재사용이 가능하다는 것이다. 다형성이 보장될 경우, 송신자가 수신자의 종류를 모르더라도 메시지를 전송하는 것이 가능하며, 송신자에게 어떠한 영향 없이 수신자를 교체, 추가하는 것이 가능하다. 따라서 책임을 완수할 수 있는 새로운 유형의 객체를 정의함으로써 객체들의 협력의 범위를 넓힐 수 있다.

  • 다형성은 송신자와 수신자 간의 객체 타입에 대한 결합도를 메시지에 대한 결합도로 낮춤으로써 달성된다.
  • 상위 클래스 타입의 객체 참조 변수에서 하위 클래스가 오버라이딩한 메서드를 자동으로 호출해주기 때문에 코드를 깔끔하게 유지할 수 있다.

🧐 Java에서의 다형성의 예시를 살펴보자!

Java에서는 한 타입의 참조 변수로 여러 타입의 객체를 참조하는 것을 허가하여 다형성을 구현하였다.

public class Tv {
    boolean power;
    int channel;

    void power() {
        power = !power;
    }

    void channelUp() {
        ++channel;
    }

    void channelDown() {
        --channel;
    }
}

class SmartTv extends Tv {
    boolean caption;

    void displayCaption(String text) {
        if (caption) {
            System.out.println(text);
        }
    }
}

예를 들어 위와 같이 Tv와 Tv 클래스를 상속하는 SmartTv 클래스가 있다고 하자.
인스턴스의 자료형과 참조변수의 자료형을 통일시킨다면 Tv t = new Tv(); 혹은 SmartTv s = new SmartTv();로 인스턴스를 생성할 수 있다.

그런데 java에서는 다형성이 구현되어있기 때문에 조상 타입의 참조변수로 자손 타입의 인스턴스를 참조하는 것이 가능하다. (반대는 안 된다.)

SmartTv s = new SmartTv();
Tv t = new SmartTV();

단, 한 가지 주의해야 할 사항이 있다.

SmartTV 인스턴스의 참조변수 타입을 Tv로 지정하면, SmartTv(생성되는 인스턴스)가 갖고있는 멤버를 모두 사용할 수 있는 것이 아닌 Tv(참조변수)에 정의되어 있는 멤버만 사용할 수 있다는 것이다. 따라서 위와 같이 인스턴스를 생성한다면 SmartTv에만 있는 caption과 displayCaption을 t.caption 또는 t.displayCaption과 같은 형태로 사용할 수 없다.

Overriding

멤버의 사용 범위와 비슷하게, 상위 클래스 타입의 객체 참조 변수를 사용하더라도 하위 클래스에서 overriding한 메서드가 호출된다.

class Parent {
    void parentMethod() {
    	System.out.println("I love 🍍");
    }
}

class Child extends Parent {
    // overriding (재정의: 상위 클래스의 메서드와 같은 메서드 이름, 같은 인자 리스트)
    void parentMethod() {
    	System.out.println("I love 🍇"); 
    } 

    // overloading (중복정의: 같은 메서드 이름, 다른 인자 리스트)
    void parentMethod(int i) {
    	System.out.println("I love 🍎");
    } 
}

Parent p = new Child();와 같이 부모 클래스 타입의 참조변수로 Child 클래스의 인스턴스를 참조한다음 p.parentMethod();를 실행하면 I love 🍇가 출력되는 것을 확인할 수 있다.

매개변수의 다형성

  • 메서드의 매개변수가 조상타입의 참조변수로 정의되어 있다면, 어떤 자손타입의 참조변수라도 매개변수로 들어갈 수 있다.
  • 예를 들어 Product라는 조상 클래스와 Product를 상속하는 Tv와 Computer 클래스가 있다고 가정해보자.
  • 아래와 같이 Product를 매개변수로 받는 buy메서드를 정의한다면, Tv 또는 Computer 객체 또한 buy메서드의 매개변수로 받아들일 수 있다.
void buy(Product p) {
    money = -= p.price;
    bonusPoint += p.bonusPoint;
}

Source

  • 자바의 정석 (남궁성 저)
  • 객체지향의 사실과 오해 (조영호 저)
  • 스프링 입문을 위한 자바 객체 지향의 원리와 이해 (김종민 저)
  • 다형성 wikipedia

4개의 댓글

comment-user-thumbnail
2021년 1월 15일

아직은 잘모르는 개념이지만 나중에 도움이 될 것 같아서 정독 했습니다!
필요한 개념이 되면 다시 찾아올게요!

1개의 답글
comment-user-thumbnail
2021년 1월 15일

정리 꼼꼼하게 잘 하셨네요~ 저두 이제 막 공부하던 부분이라 다시 한번 내용 정독했습니다! 매번 열정의 자극을 주셔서 감사해요!

1개의 답글