자바(JAVA)

자바 - 객체 지향(3) : 다형성(Polymorphism)

BlueNoa 2023. 9. 18. 21:07
728x90
반응형

<목차>

 


• 다형성(Polymorphism)이란?

다형성은 객체 지향 프로그래밍의 중요한 개념 중 하나로, 여러 클래스가 동일한 인터페이스 또는 기본 클래스를 공유함으로써 코드의 유연성을 확보하고 재사용성을 높이는 데 사용한다. 이전에 다룬 게시글에 나온 방법들이 전부 다형성과 관련된 내용들이다. 예를 들어서 다음과 같은 내용들을 참고하면 좋다.

[참고 - 메서드 오버라이딩] : 상속 마지막 내용에 있다.(더 보기 참고)

[참고 - 인터페이스] : 위 링크에 포함된 내용이다.

[참고 - 상위 클래스 참조 변수] : 상속 내용에 포함되어 있다.

 

<예시>

// 인터페이스1
interface Explore {
    String getItem();

    default void printItem() {
        System.out.printf("i found %s\n", getItem());
    }
}
// 인터페이스2
interface Use {
    void use();
}

// 인터페이스를 상속 받은 인터페이스
interface ExploreAndUse extends Explore, Use {
}

class Item {
    String name;
    void setName(String name) {
        this.name = name;
    }
}

class Fishing extends Item implements Explore, Use {
    public String getItem() {
        return "fish";
    }

    public void use() {
        System.out.println("미끼를 사용하여 낚시를 하였습니다.");
    }
}

class Hunting extends Item implements ExploreAndUse {
    public String getItem() {
        return "토끼";
    }

    public void use() {
        System.out.println("함정을 설치하여 사냥을 하였습니다.");
    }
}

class Inventory {
    void notification(Explore explore) {
        System.out.println("아이템 : " + explore.getItem());
    }
}

class UseList {
    void list(Use use) {
        use.use();
    }
}

public class sample {
    public static void main (String[] args) {
        Fishing fishing = new Fishing();
        Hunting hunting = new Hunting();

        UseList useList = new UseList();
        useList.list(fishing); useList.list(hunting);

        Inventory inventory = new Inventory();
        inventory.notification(fishing); fishing.printItem();
    }
}

<결과>

미끼를 사용하여 낚시를 하였습니다.
함정을 설치하여 사냥을 하였습니다.
아이템 : fish
i found fish

 

만약 다형성을 이용하지 않는다고 하면 낚시인지 사냥인지에 따라 if문을 사용하여 모든 경우에 대해 정리해야 할 것이다.

 

반응형

• 다형성의 종류

다형성에도 종류가 있다. 위에서 설명한 메서드 오버라이딩, 인터페이스, 상속 등은 다형성을 구현하는 방법에 대한 설명이다. 다형성의 종류로는 컴파일 시 다형성, 런타임 다형성, 인터페이스 다형성이 있다. 인터페이스 다형성은 구현 방법에서 설명한 인터페이스와 동일한 내용이므로 넘어가고, '컴파일 시 다형성' '런타임 다형성'에 대해 살펴보자.

(사실 이름만 어렵지 이미 다른 예시에서 다 봤던 내용들이다.)

 

1. 컴파일 시 다형성(Compile-time Polymorphism)

컴파일 시 다형성은 메서드 오버로딩(Overloading)을 통해 구현된다. 메서드 오버로딩은 동일한 메서드 이름을 가지고 있지만 매개변수의 개수 또는 타입에 따라 다르게 정의한다. 컴파일러는 호출된 메서드를 컴파일 시점에서 결정하게 된다.

 

<예시 - 컴파일 시 다형성>

더보기
class AddCalcul {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return  a + b;
    }
}

public class sample {
    public static void main (String[] args) {
        AddCalcul addCalcul = new AddCalcul();

        int result1 = addCalcul.add(3, 5);
        System.out.println("정수 합 : " + result1);
        double result2 = addCalcul.add(3.5, -2.7);
        System.out.println("실수 합 : " + result2);
    }
}

<결과>

정수 합 : 8
실수 합 : 0.7999999999999998

 

2. 란타임 다형성(Runtime Polymorphism)

런타임 다형성은 메서드 오버라이딩(Overriding)을 통해 구현된다. 메서드 오버라이딩은 슈퍼클래스의 메서드를 서브 클래스에서 재정의하는 것을 의미한다. 런타임 다형성은 객체의 실제 타입을 기반으로 메서드 호출을 결정한다.

 

<예시 - 런타임 다형성>

더보기
class Coffee {
    void make() {
        System.out.println("커피를 만듭니다.");
    }
}

class Americano extends Coffee {
    void make() {
        System.out.println("아메리카노를 만듭니다.");
    }
}

public class sample {
    public static void main (String[] args) {
        Coffee coffee = new Americano();
        coffee.make(); // 결과 : 아메리카노를 만듭니다.
    }
}
728x90

• 업캐스팅과 다운캐스팅

자바의 다형성은 업캐스팅(Upcasting)다운캐스팅(Downcasting) 두 가지 형태로 나뉜다.

 

1. 업캐스팅(Upcasting)

업캐스팅은 서브 클래스(하위 클래스)의 객체를 슈퍼 클래스(상위 클래스) 타입으로 형변환하는 것을 의미한다.

업캐스팅은 자동으로 이루어지며 명시적인 형변환 연산자가 필요하지 않다. 그렇기 때문에 슈퍼 클래스 타입의 참조 변수로 서브 클래스 객체를 참조할 수 있게 된다.

 

<예시 - 업캐스팅>

더보기

class Car {
    void drive() {
        System.out.println("주행 시작");
    }
}

class Tesla extends Car {
    @Override
    void drive() {
        System.out.println("NOA 주행 시작");
    }

    void autoParking() {
        System.out.println("자동 주차");
    }
}

public class sample {
    public static void main (String[] args) {
        Car car = new Tesla(); // 업캐스팅 : 서브 클래스 객체를 슈퍼 클래스 타입으로 형변환
        car.drive(); // 출력 결과 : "NOA 주행 시작"
        // car.autoParking; <- 에러 발생 : 슈퍼 클래스에서는 없는 메서드이기 때문
    }
}

 

2. 다운캐스팅(Downcasting)

다운캐스팅은 업캐스티된 객체를 다시 원래의 서브 클래스 타입으로 형변환하는 것을 의미한다.

다운캐스팅은 명시적인 형변환 연산자를 사용하여 이루어진다. 단, 사용할 때 주의할 점이 있다. 올바른 객체 타입인지 확인을 하기 위해 'instanceof' 연산자를 사용해야 한다.

 

<예시 - 다운캐스팅>

더보기

class Car {
    void drive() {
        System.out.println("주행 시작");
    }
}

class Tesla extends Car {
    @Override
    void drive() {
        System.out.println("NOA 주행 시작");
    }

    void autoParking() {
        System.out.println("자동 주차");
    }
}

public class sample {
    public static void main (String[] args) {
        Car car = new Tesla(); // 업캐스팅 : 서브 클래스 객체를 슈퍼 클래스 타입으로 형변환
        car.drive(); // 출력 결과 : "NOA 주행 시작"
        // car.autoParking; <- 에러 발생 : 슈퍼 클래스에서는 없는 메서드이기 때문

        if (car instanceof Tesla) { // 객체 확인 -> 참이기 때문에 실행
            Tesla tesla = (Tesla) car; // 다운캐스팅
            tesla.drive(); tesla.autoParking();
        }
    }
}

 

이렇게 업캐스팅과 다운캐스팅에 대해 알아보았다. 업캐스팅은 코드의 유연성을 위해 다양한 서브 클래스 객체를 만들어 내고, 이들을 동일한 슈퍼 클래스 타입으로 다룰 수 있는 확장성을 갖게 해 준다. 즉, 새로운 서브 클래스를 추가하거나 기존 서브 클래스를 대체하는 데 더 쉬워진다는 것이다. 이는 곧 설계의 유연성으로 이어진다. 

 

 

 

 

 

 

 

 
728x90
반응형