프로그래밍 언어/Java

[JAVA] 업캐스팅(up casting), 다운캐스팅(down casting) Casting을 하는 이유는? 다형성?

반응형

기본적으로 캐스팅은 서로 관련 없는 데이터끼리는 변환되지 않는다.

예를 들어서boolean a = (int) 1; boolean 자료형과 int자료형은 서로 타입이 일치하지 않은 데이터 이기 때문에 되지 않는다.

 

참조형 데이터 역시 마찬가지이다. 자 그럼 참조형 데이터가 서로 관련이 있다는 것은?

1. 상속관계

2. 인터페이스를 사용해서 확장이 된 경우

이 글에서는 상속관계를 통해 캐스팅을 확인해보도록 하겠습니다.

 

상속관계의 경우 슈퍼클래스와 서브클래스가 있을 때 서브클래스는 슈퍼클래스보다 가지고 있는 많이 있습니다.

데이터의 양 : 서브클래스 > 슈퍼클래스 (서브클래스는 슈퍼클래스의 데이터를 전부 상속받았기 때문에)

이론적으로 쉽게 생각해보면 서브클래스는 슈퍼클래스의 데이터를 전부 사용할 수 있는데, 반대로 슈퍼클래스는 서브클래스에만 있는 데이터를 사용할 수 없습니다.

 

업캐스팅(Up casting) = [서브클래스가 슈퍼클래스가 되는 것, 묵시적 형 변환]

서브클래스는 슈퍼클래스의 모든 특성을 상속받기 때문에, 서브클래스는 슈퍼클래스가 될 수 있습니다.

즉, 서브클래스의 객체가 슈퍼클래스 타입으로 형 변환되는 것을 말합니다.

 

코드로 예를 들어보겠습니다.

Jcompany라는 회사에 MarketingTeam(마케팅 팀)과 PersonnelTeam(인사 팀)이 있습니다.

슈퍼클래스 = Jcompany

서브클래스 = MarketingTeam, PersonnelTeam

class Jcompany{
    public void cMethod() {
        System.out.println("Jcompany cMethod()");
    }
    public void jMethod() {
        System.out.println("Jcompany jMethod()");
    }
}
class MarketingTeam extends Jcompany{ //마게팅팀
    public void cMethod() { //오버라이딩
        System.out.println("MarketingTeam Overriding cMethod()");
    }
    public void mMethod() {
        System.out.println("MarketingTeam mMethod()");
    }
}
class PersonnelTeam extends Jcompany{ //인사팀
    public void cMethod() { //오버라이딩
        System.out.println("PersonnelTeam Overriding cMethod()");
    }
    public void pMethod() {
        System.out.println("PersonnelTeam pMethod()");
    }
}

public class Casting{
    public static void main(String[] args) {
        Jcompany jCom;
        MarketingTeam mTeam = new MarketingTeam();
        jCom = mTeam; //업캐스팅

        jCom.cMethod();//마케팅팀의 오버라이딩된 메소드 호출
        jCom.jMethod();//j회사의 메소드 호출
        //jCom.mMethod(); 에러!!! 슈퍼클래스 인스턴스는 서브클래스 메소드 사용불가능
    }
}

실행결과

MarketingTeam Overriding cMethod()
Jcompany jMethod()

슈퍼클래스(Jcompany) 인스턴스에 서브클래스(mTeam) 객체로 형 변환하게 되면 슈퍼클래스의 인스턴스로는 슈퍼클래스 본인의 메서드는 모두 접근이 가능하지만, 서브클래스에는 접근이 불가능합니다.

 

다운캐스팅(Downcasting) = [슈퍼클래스가 서브클래스가 되는 것, 명시적 형 변환]

업캐스팅과 반대로 캐스팅하는 것을 다운 캐스팅이라고 한다.

자신의 고유한 특성을 잃은 서브클래스의 객체를 다시 복구시켜주는 것을 말하며, 업캐스팅된 것을 다시 원상태로 돌리는 것을 말한다.

다운캐스팅에서는 직접 타입을 지정해야 한다.

public class Casting{
    public static void main(String[] args) {
        Jcompany jCom;
        MarketingTeam mTeam = new MarketingTeam();
        jCom = mTeam; //업캐스팅
        
        /*
        jCom.cMethod();//마케팅팀의 오버라이딩된 메소드 호출
        jCom.jMethod();//j회사의 메소드 호출
        jCom.mMethod(); 에러!! 마케팅부서(서브 클래스) 메소드 사용불가
		*/
        
        mTeam = (MarketingTeam)jCom; //다운캐스팅
        mTeam.cMethod();
        mTeam.jMethod();
        mTeam.mMethod();
    }
}

실행결과

MarketingTeam Overriding cMethod()
Jcompany jMethod()
MarketingTeam mMethod()

JCompany jCom = new MarketingTeam(); -> 자동 형 변환, 업캐스팅, 묵시적

MarketingTeam mTeam = (MarketingTeam) jCom -> 강제 형 변환, 다운캐스팅, 명시적

 

Casting을 하는 이유는?

서브클래스 객체 생성하면 슈퍼클래스, 서브클래스 둘 다 접근이 가능한데, 도대체 캐스팅을 왜 사용할까?

도대체 왜????????

=> 상속을 받은 서브클래스가 몇 개이든 하나의 인스턴스로 묶어서 관리하기 위해서이다.

 

현재 Jcompany라는 회사 안에 마케팅팀과, 인사팀이 있습니다.

마케팅팀과 인사팀은 그 팀에 속한 직원을 관리하는 기능을 하는 클래스라고 가정

현재 예정되어있는 회사 총원은 20명인데, 어느 팀에 사원이 배정받을지 모르는 상황이다.

public class Casting{
    public static void main(String[] args) {
    /* 
       전체 사원은 20명으로 예정된 상황인데, 어느 부서에 몇 명이 배정받을지 모르기 때문에
       배열을 최대 개수로 만들어야 한다.
       1) 2개의 배열을 관리해야 하는 번거로움
       2) 배열 인덱스 관리가 쉽지 않다
    */
        

        Jcompany arrJcom[] = new Jcompany[20];
        arrPar[0] = new MarketingTeam();
        arrPar[1] = new PersonnelTeam();
        arrPar[2] = new PersonnelTeam();
        arrPar[3] = new PersonnelTeam();        

        mt = (ChildTwo) arrPar[0];

        MarketingTeam mt = (MarketingTeam) arrJcom[0];
        mt.mMthod();

        PersonnelTeam pt = (PersonnelTeam) arrJcom[1];
        pt.pMthod();
    }
}

실행결과

MarketingTeam mMethod()
PersonnelTeam pMethod()

현재 인스턴스가 2개로 나눠져 있지만, 부서가 많아져서 인스턴스가 추가가 되면 전형적인 하드코딩이 되어버린다!

자 그럼 우리가 캐스팅을 사용하는 이유는 인스턴스를 1개(슈퍼클래스)로 잡아서 서브클래스를 담아놓고 관리하기 위해서다.

슈퍼클래스가 관리할 수 있다 -> 다형성: 메서드를 각각 다른 형태로 사용 -> 슈퍼클래스를 여러 가지 형태로 만들 수 있다.

*캐스팅을 사용하는 이유(오버 라이딩의 목적) : 하나의 인스턴스(슈퍼클래스)로 서브클래스를 전부 관리할 수 있다. *

 

 

Q) 슈퍼클래스 타입으로 선언된 배열에서 무작위로 서브클래스의 인스턴스가 들어가는데 몇 번째 배열에 어떤 팀이 들어갔는지 어떻게 찾을 수 있을까요?

A) instanceof를 사용하면 된다.

    for (int i = 0; i < arrJcom.length; i++) {
        if (arrJcom[i] instanceof MarketingTeam) {
            // MarketingTeam일때 이쪽으로 들어온다. (true)
            mt = (MarketingTeam) arrJcom[i];
            mt.cMethod(); //오버라이딩된 메소드
        }else if(arrJcom[i] instanceof PersonnelTeam) {
            ((PersonnelTeam) arrJcom[i]).cMethod(); // 위와 동일한 문법
        }                
    }

참조 변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용합니다.
주로 조건문에 사용되며, instanceof의 왼쪽에는 참조 변수를 오른쪽에는 타입(클래스명)이 피연산자로 위치합니다.
그리고 연산의 결과로 boolean값인 true, false 중의 하나를 반환합니다.
instanceof를 이용한 연산 결과가 true인 경우 참조 변수가 검사한 타입으로 형 변환이 가능하다는 것을 뜻합니다.

반응형