Java - 다형성이란?

김영한님의 Java 강의로 기초다지기 - 다형성이란?

Posted by Warner on December 21, 2023

다형성

객체지향 프로그래밍의 대표적인 특징으로는 캡슐화, 상속, 다형성이 있다. 그 중에서 다형성은 객체지향 프로그래밍의 꽃이라 불린다.\

다형성(Polymorphism)은 이름 그대로 “다양한 형태”, “여러 형태”를 뜻한다.
프로그래밍에서 다형성은 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 뜻한다. 보통 하나의 객체는 하나의 타입으로 고정되어 있다. 그런데 다형성을 사용하면 하나의 객체가 다른 타입으로 사용될 수 있다는 뜻이다.

다형성을 이해하기 위해서는 크게 2가지 핵심 이론을 알아야 한다.

  • 다형적 참조
  • 메서드 오버라이딩

다형적 참조

poly1.png

poly2.png

  • 부모 타입의 변수가 부모 인스턴스를 참조한다.
  • Parent parent = new Parent()
  • Parent 인스턴스를 만들었다. 이 경우 부모 타입인 Parent를 생성했기 때문에 메모리 상에 Parent만 생성된다.(자식은 생성되지 않는다)
  • 생성된 참조값을 Parent 타입의 변수인 Parent에 담아둔다
  • parent.parentMethod()를 호출하면 인스턴스의 Parent 클래스에 있는 parentMethod() 가 호출된다.

poly3.png

  • 자식 타입의 변수가 자식 인스턴스를 참조한다.
  • Child child = new Child()
  • Child 인스턴스를 만들었다. 이 경우 자식 타입인 Child를 생성했기 때문에 메머리 상에 ChildParent가 모두 생성된다.
  • 생성된 참조값을 Child 타입의 변수인 child에 담아둔다.
  • child.childMethod()를 호출하면 인스턴스의 Child 클래스에 있는 childMethod()가 호출된다.

poly4.png

  • 부모 타입의 변수가 자식 인스턴스를 참조한다.
  • Parent poly = new Child()
  • Child 인스턴스를 만들었다. 이 경우 자식 타입인 Child를 생성했기 때문에 메모리 상에 ChildParent가 모두 생성된다.
  • 생성된 참조값을 Parent 타입의 변수인 poly에 담아둔다.

부모는 자식을 담을 수 있다.

  • 부모 타입은 자식 타입을 담을 수 있다.
  • Parent poly 는 부모 타입이다. new Child()를 통해 생성된 결과는 Child 타입이다. 자바에서 부모 타입은 자식 타입을 담을 수 있다!
    • Parent poly = new Child(): 성공
  • 반대로 자식 타입은 부모 타입을 담을 수 없다.
    • Child child1 = new Parent(): 컴파일 오류 발생

poly5.png Parent poly = new Child() 이렇게 자식을 참조한 상황에서 poly 가 자식 타입인 Child 에 있는 childMethod() 를 호출하면 어떻게 될까?

  • 컴파일 오류 발생

이런 경우 childMethod()를 호출하고 싶으면 어떻게 해야할까? 바로 캐스팅이 필요하다.

다형성과 캐스팅

다운캐스팅 poly6.png

부모는 자식을 담을 수 있지만 자식은 부모를 담을 수 없다.

  • Parent parent = new Child(): 부모는 자식을 담을 수 있다.
  • Parent parent = child // Child child 변수 : 부모는 자식을 담을 수 있다.

캐스팅

  • 업캐스팅(upcasting) : 부모 타입으로 변경
  • 다운캐스팅(downcasting) : 자식 타입으로 변경

캐스팅 용어
“캐스팅”은 영어 단어 “cast”에서 유래되었다. “cast”는 금속이나 다른 물질을 녹여서 특정한 형태나 모양으로 만드는 과정을 의미한다.

일시적 다운 캐스팅 poly7.png

((Child)poly).childMethod() //다운캐스팅을 통해 부모타입을 자식 타입으로 변환 후 기능 호출
((Child)x001).childMethod() //참조값을 읽은 다음 자식 타입으로 다운캐스팅

업캐스팅

Parent parent1=(Parent)child;
  • 업캐스팅은 생략할 수 있다.
  • 다운캐스팅은 생략할 수 없다.
  • 참고로 업캐스팅은 매우 자주 사용하기 때문에 생략을 권장한다.

다운캐스팅과 주의점

다운캐스팅이 가능한 경우 poly8.png

다운캐스팅이 불가능한 경우 poly9.png

  • new Parent()로 부모 타입으로 객체를 생성한다.
  • 메모리 상에 자식 타입은 전혀 존재하지 않는다.
  • 다운캐스팅을 하여도 메모리상에 Child가 존재하지 않으므로 사용이 불가능하다.
  • 자바에서는 이런 경우 ClassCastException 예외를 발생시킨다.

업캐스팅이 안전하고 다운캐스팅이 위험한 이유

업캐스팅의 경우 이런 문제가 절대로 발생하지 않는다. 왜냐하면 객체를 생성하면 해당 타입의 상위 부모 타입은 모두 함께 생성된다.
반면에 다운캐스팅의 경우 인스턴스에 존재하지 않는 하위 타입으로 캐스팅하는 문제가 발생할 수 있다.

컴파일 오류 vs 런타임 오류 컴파일 오류는 변수명 오타, 잘못된 클래스 이름 사용등 자바 프로그램을 실행하기 전에 발생하는 오류이다. 이런 오류는 IDE에서 즉시 확인할 수 있기 때문에 안전하고 좋은 오류이다.
반면에 런타임 오류는 이름 그대로 프로그램이 실행되고 있는 시점에 발생하는 오류이다. 런타임 오류는 매우 안좋은 오류이다. 왜냐하면 보통 고객이 해당 프로그램을 실행하는 도중에 발생하기 때문이다.

instanceof

다형성에서 참조형 변수는 이름 그대로 다양한 자식을 대상으로 참조할 수 있다. 그런데 참조하는 대상이 다양하기 때문에 어떤 인스턴스를 참조하고 있는지 확인하려면 어떻게 해야할까?

다형성과 메서드 오버라이딩

다형성을 이루는 또 하나의 중요한 핵심 이론은 바로 메서드 오버라이딩이다.
메서드 오버라이딩에서 꼭! 기억해야 할 점은 오버라이딩 된 메서드가 항상 우선권을 가진다는 점이다.
그래서 이름도 기존 기능을 덮어 새로운 기능을 재정의 한다는 뜻의 오버라이딩이다.

메서드 오버라이딩의 진짜 힘은 다형성과 함께 사용할 때 나타난다. poly10.png

  • Parent, Child 모두 value 라는 같은 멤버 변수를 가지고 있다.
    • 멤버 변수는 오버라이딩 되지 않는다.
  • Parent, Child 모두 method() 라는 같은 메서드를 가지고 있다. Child에서 메서드를 오버라이딩 했다.
    • 메서드는 오버라이딩 된다.

poly11.png

  • child 변수는 Child 타입이다. 따라서 child.value, child.method() 를 호출하면 인스턴스의 Child 타입에서 기능을 찾아서 실행한다.

poly12.png

  • parent 변수는 Parent 타입이다. 따라서 parent.value, parent.method()를 호출하면 인스턴스의 Parent 타입에서 기능을 찾아서 실행한다.

poly13.png

  • 이 부분이 중요하다.
  • poly 변수는 Parent 타입이다. 따라서 poly.value, poly.method()를 호출하면 인스턴스의 Parent 타입에서 기능을 찾아서 실행한다.
    • poly.value : Parent 타입에 있는 value 값을 읽는다.
    • poly.method() : Parent 타입에 있는 method() 를 실행하려고 한다. 그런데 하위 타입인 Child.method()가 오버라이딩 되어 있다. 오버라이딩 된 메서드는 항상 우선권을 가진다. 따라서 Parent.method()가 아니라 Child.method()가 실행된다.

오버라이딩 된 메서드는 항상 우선권을 가진다. 오버라이딩은 부모 타입에서 정의한 기능을 자식 타입에서 재정의하는 것이다. 만약 자식에서도 오버라이딩 하고 손자에서도 같은 메서드를 오버라이딩을 하면 손자의 오버라이딩 메서드가 우선권을 가진다. 더 하위 자식의 오버라이딩 된 메서드가 우선권을 가지는 것이다.

  • 다형적 참조 : 하나의 변수 타입으로 다양한 자식 인스턴스를 참조할 수 있는 기능
  • 메서드 오버라이딩 : 기존 기능을 하위 타입에서 새로운 기능으로 재정의