티스토리 뷰

JAVA/다형성(Polymorphism)

자바(JAVA) 다형성(Polymorphism) 상속 업캐스팅(UpCasting) 다운캐스팅(DownCasting)

justgodoit 2024. 7. 11. 00:43

목차

    상속 구조 클래스들 간 형변환 

    1. UpCasting

    자식 타입 > 부모 타입

    자동형변환

    ex)

    부모 = 자식객체;

    자식.부모메소드();

     

    2. DownCasting

    부모타입 > 자식타입

    강제형변환

    ex)

    ((자식)부모).자식메소드();

     

     

    다형성 

    부모타입으로부터 파생된 여러 타입의 자식 객체들을 부모타입 하나로 다룰 수 있는 기술이다.

     

    다형성 적용의 목적

     

    장점

    1. 다수의 자식 객체들을 하나로 관리할 수 있어서 용이하다.

    2. 메소드 정의 시 매개변수로 부모타입을 기술하게 되면 메소드 갯수를 줄일 수 있다.

     

     => Object 클래스에 equals메소드의 매개변수가 Object로 설정되어있다. (다형성적용)

     

    equals

    학생객체.equals(학생객체);

    도서객체.equals(도서객체);

    제품객체.equals(제품객체);

     

    자바에서 적용되는 경우가 많기 때문에 알아두어야한다.

    부모타입인 오브젝트 메소드로 되는 경우도 많아 다운캐스팅을 해야할 때도 있을 것이다.

     

    public static void main(String[] args) {
    
    	// = 대입연산자 왼쪽, 오른쪽 자료형이 같이야됨!
    		
    	System.out.println("1. 부모타입 레퍼런스로 부모객체를 다루는 경우");
    
    	Parent p1 = new Parent();
    	p1.printParent();
    	// p1 레퍼런스로 Parent에만 접근가능
    }

     

     

    자식타입 레퍼런스로 부모타입과 자식타입 레퍼런스로 둘다 접근이 가능하다.

    public static void main(String[] args) {
    
    	// = 대입연산자 왼쪽, 오른쪽 자료형이 같이야됨!
    
    	System.out.println("2. 자식타입 레퍼런스로 자식객체를 다루는 경우");
    		
    	Child1 c1 = new Child1();
    	c1.printChild1();
    	c1.printParent();
    }

     

    자동형 변환

    public static void main(String[] args) {
    	
    	System.out.println("3. 부모타입 레퍼런스로 자식객체를 다루는 경우");
    		
    	Parent p2 = new Child1(); // 자동형변환
        
    }​

     

     

    Child1 타입

    Child1 타입은 Child1 타입만 담을 수 있다.

        Child1[] arr1 = new Child1[2];
        arr1[0] = new Child1(1, 2, 4);
        arr1[1] = new Child1(2, 3, 5);

     

    Child2 타입

    Child2 타입은 Child1 타입만 담을 수 있다.

        Child2[] arr2 = new Child2[2];
        arr2[0] = new Child2(1, 2, 4);
        arr2[1] = new Child2(2, 3, 5);

     

    배열 객체를 각각 타입에 맞게만 담을 수 있다.

     

    하지만 다형성이라는 것을 적용했을 경우에 부모 자식 타입 간에 아래와 같이 진행할 수 있다.

     

    다형성 적용 후

    부모 타입의 배열을 작성한다.

    	// 다형성 적용 후 Child1 객체 2개, Child2 객체 2개 관리
    	Parent[] arr = new Parent[4]; // {Parent1, Parent2, Parent3, Parent4}
    	arr[0] = new Child1(1, 2, 4);
    	arr[1] = new Child2(4, 2, 1);
    	arr[2] = new Child2(2, 3, 1);
    	arr[3] = new Child1(2, 3, 5);

     

    하나의 부모 타입으로 여러 자식 객체들을 코드길이를 줄이며 편리하게 관리할 수 있다.

    		((Child1)arr[0]).printChild1();
    		((Child2)arr[1]).printChild2();
    		((Child2)arr[2]).printChild2();
    		((Child1)arr[3]).printChild1();

    실수로 다른 타입으로 형변환을 할 경우 오류가 발생한다.

     

    아래와 같이 작성 시 아래와 같은 오류 구문이 발생한다.

    	((Child1)arr[0]).printChild1();
    	((Child2)arr[1]).printChild2();
    	((Child2)arr[2]).printChild2();
    	((Child1)arr[3]).printChild1();
    		
    	((Child2)arr[3]).printChild1();

     

     

    ((Child2)arr[3]).printChild1(); // 부적절한 형변환시 ClassCastException 발생

     

    Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method printChild1() is undefined for the type Child2

    at cohttp://m.br.chap01_poly.run.Run.main(Run.java:55)

     

    형변환 조건문

    어떤 타입의 자식객체가 담겨있는지 알 경우

    ((자식)arr[i].자식메소드());

    for(int i=0; i<arr.length; i++) {
    	if(i == 0 || i == 3) {
    		((Child1)arr[i]).printChild1();
    	}else {
    		((Child2)arr[i]).printChild2();
    	}
    }

     

     

    그럼 어떤 타입의 자식인지 부모인지 어떤 형이 들어있는지 모르는 경우 조건식을 어떻게 작성하나요?

     

    비교대상을 다음과 같이 작성 후 참조할 클래스타입을 입력해서 비교해볼 수 있다.

     

    ex)

    for (int i = 0; i < arr.length; i++) {
    	if (arr[i] instanceof Child1) {
    		((Child1) arr[i]).printChild1();
    	} else {
    		((Child2) arr[i]).printChild2();
    	}
    }

    비교대상 : arr[i]

    연산자 : instanceof (현재 레퍼런스가 실질적으로 어떤 클래스 타입을 참조하는지 확인할 때 사용한다.

    클래스 : Child1

    if(arr[i] instanceof Child1 

     

    동적바인딩

    프로그램 실행 전 컴파일 시점에는 정적바인딩에 의해 부모클래스의 메소드를 가리키지만 프로그램이 실행되는(런타임 시점)에는 실제로 자식클래스에 오버라이딩 된 메소드가 실행된다. 아래와 같이 볼 수 있다.

     

    .java(소스코드)▶컴파일▶.class(byte코드) ▶실행 ▶ 프로그램실행

     

    Run.java (정적바인딩)

    System.out.println("============오버라이딩 적용=================");
    		
    	for(int i=0; i<arr.length; i++) {
    		arr[i].print(); 
    
    }

     

    Parent.java (부모메소드)

    public void print() {
    	System.out.println("나 부모야");
    }

     

    Child1.java (자식메소드)

    @Override
    public void print() {
    	System.out.println("나 첫번째 자식이야");
    }

     

    Run.java의 public void print의 프린트문을 출력하는데 왜 Parent.java "나 부모야"라는 내용만 있는데 실제로 프로그램이 실행되면 오버라이딩 된 내용이 나오냐? 동적바인딩이라고 한다.

     

    향상된 for문 적용