Java

다형성 (캐스팅, 메서드 오버라이딩)

공부처음하는사람 2024. 6. 10. 07:02

 

다형성이란?

다형성은 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 뜻한다. 보통 하나의 객체는 하나의 타입으로 고정되어 있는데,

다형성을 사용하면 하나의 객체가 다른 타입으로 사용될 수 있다.

 

다형적 참조 

- 부모는 자식을 품을 수 있다. (자식 클래스를 참조할 수 있다.)

 

package poly.basic;

public class PolyMain {

    public static void main(String[] args) {
        //부모 변수가 부모 인스턴스 참조
        System.out.println("Parent -> Parent");
        Parent parent = new Parent();
        parent.parentMethod();

        // 자식 변수가 자식 인스턴스 참조
        System.out.println("Child -> Child");
        Child child = new Child();
        child.childMethod();
        child.parentMethod();

        //부모 변수가 자식 인스턴스를 참조 (다형적 참조)
        System.out.println("Parent -> Child");
        Parent poly = new Child();
        poly.parentMethod();

//        Child child1 = new Parent(); // 자식은 부모를 담을 수 없다.

        //자식의 메서드는 호출할 수 없다.
//        poly.childMethod();
    }
}

 

 

다형적 참조의 한계

- 이전 상속파트에서 학습했던 내용에 인스턴스 안에서 실행할 타입을 결정하는 건 호출한 데이터 타입에 따라서 실행된다고 배웠다.

poly.childMethod( ); 코드는 Child 인스턴스 이긴 하지만 Parent 타입으로 호출했기 때문에 Child Class까지 내려가지 않는다.

Parent에서만 실행되기 때문에. childMethod( )는 실행할 수 없다. 오직 parentMethod( )만 실행이 가능하다.

출처: 김영한의 실전자바 basic - 다형성(1)

 

 

다운캐스팅

위와 같은 문제로, 데이터 타입의 문제로 poly.childMethod는 실행할 수 없다. 이 문제를 해결하기 위해서 '다운캐스팅'이 필요하다.

필요한 경우에 부모 타입을 잠깐 자식 타입으로 변경하는 방법이다.

 

package poly.basic;

public class CastingMain1 {

    public static void main(String[] args) {
        // 부모 변수가 자식 인스턴스 참조 (다형적 참조)
        Parent poly = new Child();
        // 단 자식의 기능은 호출할 수 없다.
//        poly.childMethod();

        // 다운캐스팅
        Child child = (Child) poly;
        child.childMethod();
    }
}

 

괄호와 그 사이에 타입을 지정하면 특정 타입으로 변경할 수 있다.

 

일시적 다운캐스팅

        // 일시적 다운캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅
        ((Child) poly).childMethod();

 

메서드를 호출하는 순간만 다운캐스팅을 하는 방법

 

업캐스팅

다운캐스팅과 반대로 현재 타입을 부모 타입으로 변경하는 것을 업캐스팅이라 한다.

 

package poly.basic;

public class CastingMain3 {

    public static void main(String[] args) {
        Child child = new Child();
        Parent parent1 = (Parent) child; // 업캐스팅은 생략 가능, 생략 권장
        Parent parent2 = child; // 업캐스팅 생략

        parent1.parentMethod();
        parent2.parentMethod();
    }
}

 

(부모클래스는 자식클래스를 담을 수 있다.)

업캐스팅은 괄호를 사용하지않고 생략할 수 있다. 생략을 권장한다고 한다.

 

업캐스팅은 생략하는데, 다운캐스팅은 왜 명시적으로 표현해야 할까?

 

출처: 김영한의 실전자바 basic - 다형성(1)

 

Parent 타입으로 객체가 생성되었는데, 객체가 생성 될 때 상위 클래스는 생성하지만 하위 클래스는 생성하지 않는다.

따라서 Child 인스턴스가 없으므로 캐스팅이 불가능하다. 자식 타입은 생성되지 않기때문에 개발자가 이를 인지한 상태에서

코드를 작성했다는 의미로 명시적으로 표현을 해주어야 한다.

 

 

instanceof

package poly.basic;

public class CastingMain5 {

    public static void main(String[] args) {
        Parent parent1 = new Parent();
        System.out.println("parent1 호출");
        call(parent1);

        Parent parent2 = new Child();
        System.out.println("parent2 호출");
        call(parent2);
    }

    private static void call(Parent parent) {
        parent.parentMethod();

        if (parent instanceof Child) {
            System.out.println("Child 인스턴스 맞음");
            Child child = (Child) parent;
            child.childMethod();
        }
    }
}

 

instanceof를 통해 보다 안전하게 다운캐스팅을 할 수 있다.

 

     jdk 16버전에서는 instanceOf에 변수선언까지 가능하다.
    private static void call(Parent parent) {
        parent.parentMethod();
// child 인스턴스 인경우 childMethod() 실행
        if (parent instanceof Child child) {
            System.out.println("Child 인스턴스 맞음");
            child.childMethod();
        }
    }

 

jdk16버전에선 instanceof 기능이 개선되었다고 한다.

 

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

메서드 오버라이딩의 핵심은 오버라이딩 된 메서드가 절대적으로 우선권을 가진다는 것이다.

 

package poly.overriding;

public class OverridingMain {

    public static void main(String[] args) {

        Child child = new Child();
        System.out.println("Child -> Child");
        System.out.println("Value = " + child.value);
        child.method();

        // 부모 변수가 부모 인스턴스 참조
        Parent parent = new Parent();
        System.out.println("Parent -> Parent");
        System.out.println("Value = " + parent.value);
        parent.method();

        // 부모 변수가 자식 인스턴스 참조(다형적 참조)
        Parent poly = new Child();
        System.out.println("Parent -> Child");
        System.out.println("Value = " + poly.value); // 변수 오버라이딩X
        poly.method(); // 메서드 오버라이딩O
    }
}

 

출처: 김영한의 실전자바 basic - 다형성(1)

 

필드는 오버라이딩이 불가능하다. 따라서 poly.value는 Parent의 value를 가져오게 된다.

메서드는 오버라이딩이 가능하다. 따라서 poly.method( );는 Child의 메서드를 실행한다. (오버라이딩 된 메서드는 우선권을 가지기 때문)

 

 


 

다운캐스팅과 업캐스팅, 메서드 오버라이딩을 배웠다. 다음섹션에서 다운캐스팅을 사용하는 이유에 대해 배우는데

아직까지 굳이 다운캐스팅을 해야할 이유를 못느끼고 있다.

'Java' 카테고리의 다른 글

다형성(3) - OCP  (0) 2024.06.13
다형성 (2) - 추상클래스, 인터페이스  (0) 2024.06.12
상속  (0) 2024.06.07
final  (0) 2024.06.06
접근 제어자  (0) 2024.05.28