관리 메뉴

ballqs 님의 블로그

[Java] 다형성(polymorphism) 본문

코딩 공부/Java

[Java] 다형성(polymorphism)

ballqs 2024. 7. 24. 20:48

다형성(polymorphism)이란?

다형성(polymorphism)이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다.

예를 들어 강아지나 고양이의 경우 둘 다 포유류라고 할 수 있다.

자바에서 다형성은 한 타입의 참조 변수를 통해 여러 타입의 객체를 참조할 수 있도록 하는 것이다. 즉 부모 클래스를 통해 자손 클래스의 참조 변수를 다루거나 부모 클래스가 가지고 있는 동일한 이름의 오버라이딩하여 재작성한 메소드를 참조한다.


다형성의 장점

  • 같은 메서드 이름이지만 여러 다른 실행 결과가 나옴
  • 객체지향 프로그래밍의 가장 큰 특징 중 하나
  • 하나의 부모클래스로 관리가 가능해 유지보수가 편리하다

코드 예

public class Main {
    public static void main(String[] args) {
        
        // A 인터페이스에 구현체 B 대입
        A a1 = new B();
        
        // A 인터페이스에 구현체 B를 상속받은 C 대입
        A a2 = new C();
        
    }
}

interface A { }
class B implements A {}
class C extends B {}

 

new B()로 생성하여 A라는 클래스에 담을수 있는 이유는 코드에도 설명이 적혀있지만 B가 A를 상속받았기 때문이다.

new C()로 생성해서도 A에 담을수 있는 건 C는 B를 상속했고 B는 A를 상속했기에 가능하다.

 

이러하듯 다른 자식 클래스를 추가해도 상속과 메서드 재정의를 활용하여 추가에 용이하다.

다형성이 아닌 방법으로 구현한다면 is-else if문으로 구현되고 코드의 유지보수가 어려워진다.

 

다형성의 형변환 조건

  • 서로 상속관계에 있는 부모 클래스 : 자식 클래스 사이에만 형 변환이 가능
  • 업 캐스팅(자식 클래스 타입에서 부모 클래스 타입으로 형 변환)은 생략 가능
  • 다룬 캐스팅(부모 클래스에서 자식 클래스로 형 변환)은 형 변환 연산자를 반드시 작성
public class Main {
    public static void main(String[] args) {
    	// 다운 캐스팅
        A a1 = new A();
        B b1 = (B) A; // 형 변환 연산자가 필수
        
        // 업 캐스팅
        A a2 = new C();
    }
}

interface A { }
class B implements A {}
class C extends B {}

 

 

실제로 적용해본 사례

계산기 사칙 연산 부분을 구현하고자 했다.

Operator 클래스에 operate 메소드를 만들어두고 자식 클래스는 상속을 받아 오버라이딩으로 구현했다.

각각 [+, -, /, *, %] 이며 기호별 어떤 것을 의미하는진 다들 알고 있을듯하다.

// Operator 클래스
public class Operator implements OperatorInterface{
    @Override
    public double operate(double num1, double num2) {
        return 0;
    }
}

// AddOperator 클래스(Operator 상속)
public class AddOperator extends Operator {
    @Override
    public double operate(double num1, double num2) {
        return num1 + num2;
    }
}
// DivideOperator...

// ModOperator...

// MultiplyOperator...

// SubtractOperator...

 

아래와 같은 메소드를 구축 한다.

// 반환 데이터를 Operator로 설정
public Operator calculate(char sign) {
    try {
        switch (sign) {
            case '+' :
                return new AddOperator();
            case '-' :
                return new SubtractOperator();
            case '*' :
                return new MultiplyOperator();
            case '/' :
                return new DivideOperator();
            case '%' :
                return new ModOperator();
            default:
                throw new CalculatorException();
        }
    } catch (ArithmeticException e) { // 나눗셈 연산에 분모(두번째 정수)에 0이 오면 예외처리
        System.out.println("나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다. ");
    } catch (CalculatorException e) { // 적합한 예외처리가 뭔지 몰라 작성함
        System.out.println(e.getMessage());
    }
    return null;
}

 

그리고 위의 함수를 사용한 방법은 아래와 같다.

// 사용방법
double calc = arithmeticCalculator.calculate(sign).operate(num1 , num2);

 

많이 복잡해 보이긴 하지만 Operator 반환 타입을 가진 함수를 호출하여 내부에 있는 자식 클래스중 무엇을 return 할지 정하여 리턴 후 가지고 있는 operate 함수를 통해 계산된 값을 가져오는 방법이다.

 

이렇든 다형성은 많이 복잡하고 수없이 써봐야지 알거 같다.