[기본 개념] 2 | (5.1) 다형성, 참조변수의 형변환

728x90

[기본 개념] 2 | (5.1) 다형성, 참조변수의 형변환

1> 다형성이란?

2> 참조변수의 형변환

3 instanceof연산자

4 참조변수와 인스턴스의 연결

5 매개변수의 다형성

6 여러 종류의 객체를 배열로 다루기

1. 다형성이란?

 객체지향개념에서 다형성이란 '여러 가지 형태를 가질 수 있는 능력'을 의미하며, 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현하였다.

 

조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하였다는 것이다.

 

        class Tv {

            boolean power ;       // 전원 상태(on / off)

            int channel ;            // 채널

 

            void power( )            { power = !power ; }

            void channelUp( )      {    ++channel ;     }

            void channelDown( )  {     -- channel ;     }

        }

 

        class CaptionTv extends Tv {

            String text ;            // 캡션을 보여주기 위한 메뉴얼

            void caption( )   { /* 내용 생략 */ }

        }

 

 클래스 Tv와 CaptionTv는 서로 상속관계에 있으며, 이 두 클래스의 인스턴스를 생성하고 사용하기 위해서는 다음과 같이 할 수 있다.

 

        Tv t = new Tv( ) ;

        CaptionTv c = new CaptionTv( ) ;

 

 인스턴스의 타입과 참조변수의 타입이 일치하는 것이 보통이지만, Tv와 CaptionTv클래스가 서로 상속관계에 있을 경우, 다음과 같이 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하도록 하는 것도 가능하다.

 

        Tv t = new CaptionTv( ) ;    // 조상 타입의 참조변수로 자손 인스턴스를 참조

 

 이제 인스턴스를 같은 타입의 참조변수로 참조하는 것과 조상타입의 참조변수로 참조하는 것은 어떤 차이가 있는지에 대해서 알아보도록 하자.

 

        CaptionTv c = new CaptionTv( ) ;

        Tv            t = new CaptionTv( ) ;

 

 위의 코드에서 CaptionTv인스턴스 2개를 생성하고, 참조변수 c와 t가 생성된 인스턴스를 하나씩 참조하도록 하였다.

 

 Tv타입의 참조변수로는 CaptionTv인스턴스 중에서 Tv클래스의 멤버들(상속받은 멤버포함)만 사용할 수 있다. 따라서, 생성된 CaptionTv인스턴스의 멤버 중에서 Tv클래스에 정의되지 않은 멤버, text와 caption( )은 참조변수 t로 사용이 불가능하다.

 

즉, 둘 다 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.

 

 하지만 자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은 불가능하다. 왜냐하면 존재하지 않는 멤버를 사용하고자 할 가능성이 있기 때문이다.

 

따라서 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.

2. 참조변수의 형변환

 기본형 변수와 같이 참조변수도 형변환이 가능하다. 단, 서로 상속관계에 있는 클래스사이에서만 가능하기 때문에 자손타입의 참조변수를 조상타입의 참조변수로, 조상타입의 참조변수를 자손타입의 참조변수로의 형변환만 가능하다.

 

 참조형 변수의 형변환에서는 자손타입의 참조변수를 조상타입으로 형변환하는 경우에는 형변환을 생략할 수 있다.

 

자손타입 --> 조상타입(Up-casting)     : 형변환 생략가능

자손타입 <-- 조상타입(Down-casting) : 형변환 생략불가

 

 조상클래스인 Car클래스를 상속받는 두 자손클래스 FireEngine클래스, Ambulance클래스가 정의되어 있다고 하자.

 

 FireEngine타입의 참조변수와 Ambulance타입의 참조변수 간에는 상속관계가 아니기 때문에 서로 형변환이 가능하지 않다.

 

        FireEngine  f ;

        Ambulance a ;

        a = (Ambulance) f ;     // error. 상속관계가 아닌 클래스간의 형변환 불가

        f = (FireEngine) a ;      // error. 상속관계가 아닌 클래스간의 형변환 불가

 

먼저 Car타입 참조변수와 FireEngine타입 참조변수 간의 형변환을 예로 들어보자.

 

        Car car = null ;

        FireEngine fe = new FireEngine( ) ;

        FireEngine fe2 = null ;

 

        car = fe ;                        // car = (car) fe ; 에서 형변환 생략됨. 업캐스팅

        fe2 = (FireEngine) car ;      // 형변환 생략 불가. 다운캐스팅

 

예제/CastingTest1.java

public class CastingTest1 {
    public static void main(String[] args) {
        Car car = null;
        FireEngine fe = new FireEngine();
        FireEngine fe2 = null;
        
        fe.water();
        car = fe;       // car = (car)fe;에서 형변환이 생략
//      car.water();    // 컴파일에러. Car타입의 참조변수로는 water()을 호출할수 없다.
        fe2 = (FireEngine)car;
        fe2.water();
    }
}

class Car {
    String color;
    int door;
    
    void drive() {
        System.out.println("drive, Brrrr~");
    }
    
    void stop() {
        System.out.println("stop!!!!");
    }
}

class  FireEngine extends Car {
    void water() {
        System.out.println("water!!");
    }
}
실행결과

water!!
water!!

 

1. Car car = null ;

 Car타입의 참조변수 car을 선언하고 null로 초기화한다.

 

2. FireEngine fe = new FireEngine( ) ;

 FireEngine인스턴스를 생성하고 FireEngine타입의 참조변수가 참조하도록 한다.

 

3. car = fe ;  // 조상타입 <-- 자손타입

 참조변수 fe가 참조하고 있는 인스턴스를 참조변수 car가 참조하도록 한다. fe의 값(fe가 참조하고 있는 인스턴스 주소)이 car에 저장된다. 이제 참조변수 car을 통해서도 FireEngine인스턴스를 사용할 수 있지만, fe와 달리 car는 Car타입이므로 Car클래스의 멤버가 아닌 water( )는 사용할 수 없다.

 

4. fe2 = (FireEngine) car ;  // 조상타입 --> 자손타입

 참조변수 car가 참조하고 있는 인스턴스를 참조변수 fe2가 참조하도록 한다. car에는 FireEngine인스턴스의 주소가 저장되어 있으므로 fe2에도 FireEngine인스턴스의 주소가 저장된다. 이제는 car와는 달리, fe2는 FireEngine타입이므로 water( )도 사용할 수 있다.

 

서로 상속관계에 있는 타입간의 형변환은 양방향으로 자유롭게 수행될 수 있으나,

참조변수가 가리키는인스턴스의 자손타입으로 형변환은 허용되지 않는다.

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90