Java - OOP 다형성

Kwon Yongho·2023년 12월 15일
0

Java

목록 보기
4/6
post-thumbnail

다형성(Polymorphism)

  • 다형성이란 여러 개를 의미하는 poly와 형태 또는 실체를 의미하는 morphism의 결합어로, 하나의 객체가 여러 가지 형태를 가질 수 있는 것을 의미한다.
  • 자바에선 대표적으로 오버로딩, 오버라이딩, 업캐스팅, 다운캐스팅, 인터페이스, 추상메소드, 추상클래스 방법이 모두 다형성에 속하다고 생각하면 된다.

다형성의 장점

  • 유지보수 : 여러 객체를 하나의 타입으로 관리할 수 있어 유지보수가 용이하다.
  • 재사용성 : 객체의 재사용이 쉬워 재사용성이 높아진다.
  • 느슨한 결합 : 클래스 간의 의존성을 줄여 확장성은 높아지고 결합도는 낮아진다.
    부모 클래스 타입으로 자식 클래스를 생성

1. 참조변수의 다형성

여기 그냥 자동차와 자동주행이 가능한 자동차가 있다고 가정하겠습니다.
AutomatedCar 클래스에서는 Car 클래스의 기본 기능들을 사용하기 위해 상속하고 자율 주행 모드를 전환하고 해제하는 기능을 추가하였습니다.

class Car {
    void drive(); // 주행
    void refuel(); // 주유
}

class AutomatedCar extends Car {
    void enableAutonomousMode(); // 자율 주행 모드 전환
    void disableAutonomousMode(); // 자융 주행 모드 해제
}

Main

public class Main {
    public static void main(String[] args) {
    	Car car = new Car();
        Car automatedCar = new AutomatedCar();
    }
}
  • 보통 일반적으로 동일한 클래스의 타입의 참조 변수를 생성하여 초기화해왔지만

1-1. 업캐스팅

	Car car = new AutomatedCar();
  • 부모 자식 상속 관계에 있으면 다음과 같이 부모 타입으로 자식 클래스 타입을 받아 초기화 할 수 있습니다.()
  • 하지만 해당 관계에서는 Car 클래스의 기본 기능인 drive(), refuel() 밖에 사용 할 수 없습니다.
  • 상위 클래스 타입의 참조 변수로 하위 클래스의 객체를 참조하는 다형성의 핵심적인 부분입니다.

업캐스팅, 다운캐스팅, 형변환에 대해서는 자세히 다루지는 않겠습니다.

2. 자료형 다형성

위에 코드의 참조변수의 다형성은 사실 자식 클래스에 있는 기능은 사용도 못하고 부모 클래스의 기본 기능밖에 사용하지 못합니다. 좋아 보이는게 하나도 없는데 왜 쓰는 것일까요? 바로 자료형의 묶음입니다.

간단한 Animal 클래스를 상속받는 다양한 동물들이 있다고 가정하고 해당 동물들이 모두 울음소리를 출력하게 해보겠습니다.

// 동물을 나타내는 부모 클래스
class Animal {
    protected String sound;

    public Animal(String sound) {
        this.sound = sound;
    }

    public void makeSound() {
        System.out.println(sound);
    }
}

// 각각의 동물을 나타내는 자식 클래스들
class Dog extends Animal {
    public Dog() {
        super("멍멍!");
    }
}

class Cat extends Animal {
    public Cat() {
        super("야옹!");
    }
}

class Duck extends Animal {
    public Duck() {
        super("꽥꽥!");
    }
}


public class PolymorphismExample {
    public static void main(String[] args) {
        // 각 동물의 객체를 생성하고 울음 소리 출력
        Dog myDog = new Dog();
        myDog.makeSound();

        Cat myCat = new Cat();
        myCat.makeSound();

        Duck myDuck = new Duck();
        myDuck.makeSound();
    }
}
  • 각 동물들은 타입이 다르기 때문에 모두 객체를 생성해서 makeSound() 메서드를 출력 해주는 방법 밖에 없습니다.
  • 하지만 Animal 부모 클래스에 상속 관계를 이용하여 각 타입을 Animal 클래스로 묶는다면
public class PolymorphismExample {
    public static void main(String[] args) {
        // 다형성을 활용하여 여러 동물을 하나의 배열에 담음
        Animal[] animals = new Animal[3];
        animals[0] = new Dog();
        animals[1] = new Cat();
        animals[2] = new Duck();

        // 배열을 순회하면서 각 동물의 소리를 출력
        for (Animal animal : animals) {
            animal.makeSound();
        }
    }
}
  • 여러 동물을 하나의 자료형의 배열에 넣을 수 있습니다.

3. 매개변수 다형성

다형성은 변수의 타입 뿐만 아니라 매개변수에서도 찾아 볼 수 있습니다.

// 동물을 나타내는 인터페이스
interface Animal {
    void makeSound();
}

// 다양한 동물을 나타내는 클래스들
class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }
}

class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

// 동물 소리를 출력하는 유틸리티 클래스
class AnimalSoundUtil {
    // 매개변수로 Animal 인터페이스를 구현한 객체를 받아 소리를 출력
    public static void makeAnimalSound(Animal animal) {
        animal.makeSound();
    }
}

// 실행 클래스
public class InterfaceParameterPolymorphismExample {
    public static void main(String[] args) {
        // 다형성을 이용하여 다양한 동물 객체를 매개변수로 전달
        AnimalSoundUtil.makeAnimalSound(new Dog()); // Dog 객체 전달
        AnimalSoundUtil.makeAnimalSound(new Cat()); // Cat 객체 전달
    }
}

4. 메서드 다형성

메서드를 확장하거나 재정의하는 overloading / overriding도 메서드가 다형해 지기 때문에 다형성의 특징 중 하나로 볼 수 있습니다.

4-1. 오버로딩(Overloading)

  • 자바의 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메소드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있다.
  • 메소드의 이름이 같고, 매개변수의 개수나 타입이 달라야 한다. 주의할 점은 '리턴 값만' 다른 것은 오버로딩을 할 수 없다는 것이다.

4-2. 오버라이딩(Overriding)

  • 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것을 오버라이딩이라고 한다.
  • 오버라이딩은 부모 클래스의 메소드를 재정의하는 것이므로, 자식 클래스에서는 오버라이딩하고자 하는 메소드의 이름, 매개변수, 리턴 값이 모두 같아야 한다.
class Animal {
    public void makeSound() {
        System.out.println("동물 소리");
    }

    public void specialAction() {
        System.out.println("동물의 특별한 행동");
    }

    public void specialAction(String action) {
        System.out.println("동물의 특별한 행동: " + action);
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }

    @Override
    public void specialAction() {
        System.out.println("개의 특별한 행동: 짖기");
    }

    public void specialAction(int distance) {
        System.out.println("개의 특별한 행동: " + distance + "m 뛰기");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }

    @Override
    public void specialAction() {
        System.out.println("고양이의 특별한 행동: 발톱 갈기");
    }

    public void specialAction(String action, int times, boolean loud) {
        if (loud) {
            System.out.println("고양이의 특별한 행동: " + action + " " + times + "번 반복 (크게 소리 내어)");
        } else {
            System.out.println("고양이의 특별한 행동: " + action + " " + times + "번 반복");
        }
    }
}

public class MethodPolymorphismExample {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        Cat myCat = new Cat();

        // 각 동물의 소리 출력
        myDog.makeSound();
        myCat.makeSound();

        // 각 동물의 특별한 행동 출력
        // 오버 라이딩
        myDog.specialAction();
        myCat.specialAction();

        // 각 동물의 특별한 오버로딩 메서드 호출
        myDog.specialAction(3);
        myCat.specialAction("뛰기", 3, true);
    }
}

참고

0개의 댓글