Java 다형성 - 메소드 오버라이딩

객체 지향 특징으로 다형성 상속 캡슐 추상화가 있으며 이 중에 핵심은 메소드 오버라이딩이다.
기존의 배워왔던 오버라이딩은 같은 메소드 이름의 기존 기능을 덮어씌우고 새로운 기능으로 재정의되는 것이다.

다형성에서의 메소드 오버리이딩 특징은 오버라이딩된 메소드가 항상 우선권을 갖고 있다.

다음 코드로 다형성과 메소드 오버라이딩은 사용해보도록 한다.

  • Parent, Child 모두 value 멤버 변수를 갖고 있다.
    • 멤버 변수는 오버라이딩 되지 않는다.
  • Parent, Child 모두 moethod 메소드를 갖고 있다. Child 클래스는 method 오버라이딩을 재정의되었다.
    • 메소드는 오버라이딩이 되어 우선권을 갖는다.

메소드 오버라이딩 - 다형성 코드 예제

Parent, Child 클래스를 만들고 메인에서 실행하였을 때 메소드 오버라이딩을 살펴보도록 한다.

Parent.java

public class Parent {
    public String value = "p";

    public void method() {
        System.out.println("This is Parent. Value: " + value);
    }
}

Child.java

public class Child extends Parent {
    public String value = "c";

    @Override
    public void method() {
        System.out.println("This is Child. Value: " + value);
    }
}

Child To Child

자식 인스턴스를 자식 변수에게 참조한 경우이다.

Main.java

public class Main {
    public static void main(String[] args) {
        // 자식 인스턴스는 자식에게 참조
        Child child = new Child();
        System.out.println("===Child To Child===");
        System.out.println("value: " + child.value);
        child.method();
    }
}

실행결과

===Child To Child===
value: c
This is Child. Value: c

child 변수는 인스턴스 내부에서 Child 타입의 Child.method() 메소드를 호출한다.

Parent To Parent

부모 인스턴스를 부모 변수에게 참조한 것이다.

Main.java

public class Main {
    public static void main(String[] args) {
        // 부모 인스턴스는 부모에게 참조
        Parent parent = new Parent();
        System.out.println("===Parent To Parent===");
        System.out.println("value: " + parent.value);
        parent.method();
    }
}

실행결과

===Parent To Parent===
value: p
This is Parent. Value: p

Parent To Child

새로 선언한 poly 변수는 Parent 변수이다. 따라서 poly.value, poly.method() 호출한 경우 Parent 클래스에서 찾아 기능을 호출한다.

  • poly.value: Parent 인스턴스 타입에서 value 값을 찾는다.
  • poly.method(): Parent 인스턴스 타입에서 method() 메소드를 찾는다.
    • child 타입이 method() 메소드가 오버라이딩이 되어있다.
    • 오버라이딩된 메소드는 우선권이 높다. Parent.method() 메소드가 아닌 child.method() 메소드를 호출한다.

Main.java

public class Main {
    public static void main(String[] args) {
        // 자식 인스턴스는 부모에게 참조
        Parent poly = new Child();
        System.out.println("===Parent To Child===");
        System.out.println("value: " + poly.value);
        poly.method();
    }
}

실행결과

===Parent To Child===
value: p
This is Child. Value: c

마술처럼 결과 값이 Parent 메소드가 아닌 Child 의 메소드를 호출한 모습을 볼 수 있다.

Parent 타입의 parent 변수는 인스턴스 내부에서 Parent 타입을 찾고 Parent.value 변수 값을 출력한다. 그리고 Parent.method() 메소드는 호출 전 오버라이딩이 있는지 살펴본다. Child.method() 가 있으므로 이 메소드 우선권을 갖게되고 호출하게 된다.

그 결과. value 변수는 Parent타입의 값을 출력하였고, method() 메소드는 Child 타입의 메소드를 호출하였다.

💡
변수는 오버라이딩이 안된다.

이것이 다형적 참조와 메소드 오버라이딩이다.

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

이 두 개의 기능이 여러가지 디자인 패턴을 만들어냈으므로 알아야 할 컴퓨터 사이언스이다.