[OOP] 다형성(Polymorphism)이란 ?

이석환·2024년 2월 16일

개념 정리

목록 보기
5/6
post-thumbnail

다형성

다형성이란 프로그램 언어 각 요소들(상수, 변수, 식, 객체, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질을 가리킨다.

위키피디아에서 발췌해온 내용이다.
해당 정의를 봤을 때, 쉽게 이해하기는 어려울 것이다.
필자의 상속 게시물에서 다형성이 등장했다.

코드를 통해 미리 설명하자면 다음과 같다.

public static void main(String[] args) {
        final 첫째 firstBorn = new 첫째("철수");
        final 둘째 secondBorn = new 둘째("영희");

        final List<HwanFamily> hwanFamily = List.of(firstBorn, secondBorn);

        for (HwanFamily familyMember : hwanFamily) {
            familyMember.eatBreakfastWithFamily();
            familyMember.eatDinnerWithFamily();
            System.out.println();
        }
    }

위와 같이 하나의 타입에 여러 객체를 대입할 수 있는 성질이다.
다형성은 다음과 같은 장점을 가진다.

  • 상속을 통해 기능을 확장하거나 변경하는 것을 가능하게 해준다.
  • 같은 클래스 내에 코드의 길이를 줄일 수 있다.

오버로딩 (Overloading)

오버로딩이란 한 클래스 내에 동일한 이름을 가진 메소드가 있더라도, 매개 변수의 개수 혹은 타입이 다른 경우에 같은 이름을 사용해서 메소드를 정의할 수 있는 것을 의미한다.

오버로딩은 컴파일 시점에 함수의 인자를 바탕으로 적절한 메소드를 찾기 때문에, 이를 정적 다형성이라고도 부른다.

오버로딩의 조건
- 한 클래스 내에서 메소드 명이 동일해야 한다.
- 매개 변수의 개수 또는 타입이 달라야 한다.
- 매개변수는 같고, 리턴 타입이 다른 경우는 오버로딩이 성립되지 않는다. 
(리턴 타입은 오버로딩에 영향을 주지 않는다.)

예시

public class Main {
    public int overloading(int a, int b) {
        return a + b;
    }

    public double overloading(double a, double b) {
        return a + b;
    }

    public String overloading(String a, String b) {
        return a + b;
    }

    public void overloading(List<String> list) {
        for (String s : list) {
            System.out.println(s);
        }
    }

    public static void main(String[] args) {
        Main main = new Main();
        System.out.println(main.overloading(1, 2));
        System.out.println(main.overloading(1.5, 2.5));
        System.out.println(main.overloading("Hello ", "World"));
        main.overloading(List.of("I'm", "Seokhwan"));
    }
}


예시를 살펴 보면, overloading 이라는 동일한 메서드 명을 가진다.
하지만, 매개 변수의 개수나 타입이 다름에 따라 다른 동작을 수행하는 것을 알 수 있다.

장점

  • 다양한 데이터 타입을 처리할 수 있다.
    매개 변수 값을 다양하게 받기 때문에 다양한 처리가 가능하다.
    같은 기능이지만, 입력 값을 다르게 하고 싶은 경우에 매개 변수의 타입에 맞춰서 다른 이름을 가진 메소드를 생성할 필요가 없어진다.

  • 코드의 가독성이 좋아진다.
    유사한 기능을 의미하는 동일한 이름의 메소드를 묶을 경우, 타인이 이해하기 쉬워진다.

  • 기능 예측이 쉬워진다.
    오버로딩을 사용하는 이유 중에 한 가지로, 입출력 값의 타입이 다르지만 같은 기능을 하는 경우이다. 메소드명이 동일함으로써 유사한 기능을 빠르고 쉽게 예측할 수 있다.

println()

오버로딩의 대표적인 예는 println()이다.
실제로 Java에서 println() 메소드를 뜯어보면 PrintStream Class에서 매개 변수에 따라 추력할 수 있도록 여러 개의 오버로딩된 println() 메소드를 정의하고 있다.

오버라이딩 (Overriding)

오버라이딩이란 상속 관게에서 자식 클래스가 부모 클래스의 메소드를 재정의하는 것을 의미한다.
상속받은 메소드를 그대로 사용하거나, 자식 클래스에서 상황에 맞게 변경이 가능한 경우에 사용한다.

@Override 어노테이션은 오버라이딩을 검증하는 기능을 한다.
코드를 검색했을 때, 오버라이딩이 실제로 시행되지 않았다면 컴파일시에 오류를 출력한다.

오버라이딩은 런타임에 객체의 타입에 따라 적절한 메소드를 동적으로 호출하기 때문에, 이를 동적 다형성이라고도 부른다.

오버라이딩 조건
- 상속 관계
- 부모 클래스의 메서드와 동일한 이름, 매개 변수, 리턴 타입을 가져야 한다.
- 부모 클래스와 같거나 더 넓은 범위의 접근 제어자를 설정해야 한다.

예시

public class Main {
    static class Car {
        public void sound() {
            System.out.println("자동차는 부우우웅하고 달립니다.");
        }
    }

    static class Hyundai extends Car {
        @Override
        public void sound() {
            System.out.println("현대차: 부우우웅");
        }
    }

    static class Kia extends Car {
        @Override
        public void sound() {
            System.out.println("기아차: 부우우웅");
        }
    }

    public static void main(String[] args) {
        List<Car> cars = List.of(new Car(), new Hyundai(), new Kia());
        for (Car car : cars) {
            car.sound();
        }
    }
}

Hyundai, Kia 클래스는 Car 클래스의 sound()를 재정의(오버라이딩)하여 다르게 출력한다.

장점

  • 확장성과 유연성
    오버라이딩을 통해 자식 클래스는 부모 클래스의 기능을 확장하거나 변경할 수 있다.
    부모 클래스의 메서드를 수정하지 않고, 자식 클래스에서만 변경된 동작을 정의할 수 있기 때문에 코드의 유지 보수성이 증가한다.

  • 다형성 구현
    부모 클래스 타입으로 선언된 객체에 실제 자식 클래스의 인스턴스를 할당하여, 실행 시에 동적으로 적절한 메서드를 호출할 수 있다.

  • 가독성과 간결성
    메서드의 동작을 명확하게 재정의하기 때문에 코드의 가독성을 증가시키고, 부모 클래스와 동일한 메서드를 사용하기 때문에 코드의 일관성과 간결성을 유지할 수 있다.

References
http://wiki.hash.kr/index.php/오버로딩
https://highright96.tistory.com/96

profile
반갑습니다.

0개의 댓글