Programming/JAVA

[JAVA] 다형성 / 형변환 / 관련 예제

Jayna. 2023. 12. 27. 16:43
728x90

다형성

부모 클래스로부터 상속받은 자식클래스 타입의 객체를

부모틀래스 타입으로 형변환하여 (= 동일한 자료형이 된다.) 한 번에 다룰 수 있다.

  => 형변환을 하면 배열을 사용할 수 있음 (배열은 같은 자료형끼리만 묶어서 보관이 가능하기 때문에)

 

>> 다형성을 사용하는 이유

 1. 부모타입의 객체 배열로 다양한 자식객체들을 받을 수 있다.

    => 부모타입 하나로 자식객체들을 모두 다룰 수 있음

 2. 메소드의 개수가 줄어든다

 

결론 : 다형성을 이용할 경우 소스코드의 길이가 줄어들어서 효율성이 높아짐

728x90
public class PolyRun {

    public static void main(String[] args) {

        // =(대입연산자)의 특징
        // 양변의 자료형이 같아야 한다.

        //1. 부모꺼는 자식꺼 자식꺼는 자식꺼
        //1. 부모타입 레퍼런스로 부모 객체를 다루는 경우
        System.out.println("1. ");
        Parent p1 = new Parent();
        p1.printParent();
        //p1.printChild1(); // 자식꺼는 부모꺼 아님
        //p1으로는 Parent에만 접근가능


        //2. 자식타입 래퍼런스로 자식 객체를 다루는 경우
        System.out.println("\n2. ");
        Child1 c1 = new Child1();
        c1.printChild1();  // 자식꺼는 자식꺼
        c1.printParent();  // 부모꺼는 자식꺼
        //c1으로는 Parent, Child1에 둘다 접근가능

        //3. 부모타입 레퍼런스로 자식객체를 다루는 경우 => 형변환, 다형성이 적용된 개념
        System.out.println("\n3. ");
        Parent p2 = /*(Parent)*/ new Child1();
        p2.printParent();
        //p2.printChild1();
        //p2로는 Parent메인 접근이 가능

        // 양쪽의 자료형이 다름에도 오류가 나지 않음
        // 왜? Parent로 자동형변환이 되었으니까
        // 상속구조에서는 클래스 형변환이 가능하다

        ((Child1)p2).printChild1();
        /*
         * 클래스 간의 형변환
         *  - 상속구조일 경우에만 클레스 간의 형변환이 가능하다.
         *  
         *  1. UpCasting
         *                        자식타입 => 부모타입
         *                        생략이 가능하다.
         *  2. DownCasting
         *                        부모타입 => 자식타입
         *                        생략이 불가능하다.                       
         */


        // 다형성을 사용하는 이유는?
        // 배열을 써보자
        // 배열의 특징 :  한 종류의 자료형인 값들을 묶어서 관리가 가능.

        System.out.println("\n\n다형성을 접목한 배열");

        // 부모타입의 객체 배열을 만든 다음에
        // 자식들을 부모배열로 묶어보자
        Parent[] arr = new Parent[4];
        arr[0] = /*(Parent)*/ new Child1(1,2,3);
        arr[1] = /*(Parent)*/ new Child1(4,5,6);
        arr[2] = /*(Parent)*/ new Child2(7,8,9);
        arr[3] = /*(Parent)*/ new Child2(10,11,12);

        // printPatent 메소드 호출
        for(int i = 0; i<arr.length;i++) {
        arr[i].printParent();
        }


        // printChild1,2 메소드 호출하려면
        // 반복문 사용이 불가능 하다
        ((Child1)arr[0]).printChild1();
        ((Child1)arr[1]).printChild1();
        ((Child2)arr[2]).printChild2();
        ((Child2)arr[3]).printChild2();

        // Child1이었던 녀석을 Child2로 강제형변환을 한다면?
        // ((Child2)arr[0]).printChild2();   
        //ClassCastException이 발생 => 클래스 간의 형변환이 잘못되었을 경우 발생하는 에러
        // 원래 Child1인 애를 Child2로 바꾸려니까 에러가 난 것

        // 반복문과 오버라이딩 개념까지 적용해보자
        System.out.println("\n\n반복문 + 오버라이딩");

        for(int i = 0; i<arr.length; i++) {
        // 각 배열의 인덱스에 차근차근 접근
        // 각각의 배열의 인덱스를 강제형변환 => 패싱
        // 메소드 호출 => print()
        arr[i].print();
        //"부모" 가 4번 찍혀야 되는데...........?
        // 정작 결과는 오버라이딩된 print가 각각 호출이 됨

        // => 오버라이딩 특징 : 오버라이딩 개념이 적용된 메소드를 호출시
        //                   원조메소드보다 새롭게 정의된 메소드가 우선순위가 높아서 먼저 호출이 됨

        // 우리가 앞으로 객체배열을 쓸 때 오버라이딩을 이용하면 굳이 강제형변환을 안해도 된다.

        /*
         * 동적바인딩
         * 
         * - 컴바일시점 : 정적바인딩으로 현재 주소값의 자료형에 클래스에 있는 메소드를 가리킨다.
         * - 런타임시점 : 동적바인딩으로 각각의 자식클래스에 오버라이딩 된 메소드가 있을 경우 알아서 해당메소드가 실행됨
         * 
         */
        }

    }
}

 

728x90