07-1 / 타입 변환과 다형성

이전에 기본 타입의 변환에 대해 공부했다면 클래스에서도 자동 타입 변환이 있고 강제변환이 있다. 

재정의(오버라이딩)과 타입변환을 이용하면 객체 지향 프로그래밍의 매우 중요한 특징인 다형성을 구현할 수 있다. 

 

  • 다형성 정의 

사용 방법은 동일하나 다양한 객체를 이용해서 다양한 실행 결과가 나오도록 하는 성질

ex) 자동차가 타이어 사용하는 방법은 동일 - 어떤 타이어를 사용하느냐에 따라 변화

 


자동 타입 변환

클래스의 변환은 상속 관계에 있는 클래스 사이에서 발생하는데 그 중 자동 타입변환은 프로그램 실행 도중에 자동적으로 타입변환이 일어나는 것을 말한다. 

  • 자식에서 부모로? 
부모타입 변수 = 자식타입;

자식은 부모의 특징과 기능을 상속 받기 때문에 부모와 동일하게 취급 될 수 있다. 그러면 자식변수를 대입한 부모타입 변수는 부모 객체를 참조하고 있을까?

메모리 적으로 봤을 때 자식 타입을 대입한 부모 변수를 부모 객체를 참조하는 것이 아니라 자식 객체를 참조하고 있다

Cat cat = new Cat();
Animal animal = cat;

위에 두 변수 cat과 animal은 모두 동일하게 Cat객체를 참조하고 있는 것이다.

또한 바로 위의 부모가 아니더라도 상속 계층 상의 상위 타입이라면 하위 타입들이 자동 타입 변환이 일어날 수 있다. 

 

  • 부모 타입으로 자동 타입 변환 후 

부모 타입으로 자동 변환 되었다면 그때 부터는 부모 클래스에 선언된 필드와 메소드만 접근이 가능하다. 위에서 자식 객체를 참조하고 있다고 했지만 접근은 부모 클래스 멤버로만 한정되어 버리는 것이다.

하지만 이것에 대한 예외가 있는데, 메소드가 자식 클래스에서 재정의 되었다면 부모 클래스가 아닌 자식 클래스의 메소드가 호출된다. 

 

 

 


필드의 다형성

자동 타입 변환이 왜 필요할까? 다형성을 구현하기 위해서다.

 

필드 타입을 부모 타입으로 선언하면 이 필드 안에 다양한 자식 객체들을 수용할 수 있다. 그럼 이 부모타입 필드 하나로 다양한 사용결과가 나올 수 있게 된다. 이게 바로 필드의 다향성이다.

 

  • 다향성 구현의 기술적 조건 3가지 

- 자식클래스는 부모가 가지고 있는 필드와 메소드를 가지고 있어 사용 방법이 동일하다.

- 자식클래스는 부모의 메소드를 재정의해 더 우수한 실행결과가 나올수 있다.

- 자식타입은 부모타입으로 변환할 수 있다. 

 

  • 예시
부모 클래스 Tire roll()
자식 클래스 1 HankookTire roll() 오버라이딩
자식 클래스 2 KumhoTire roll() 오버라이딩

차 한대에 기본으로 Tire가 4개를 사용한다. 

Class Car{
    Tire frontLeftTire = new Tire();
    Tire frontRightTire = new Tire();
    Tire backLeftTire = new Tire();
    Tire backRightTire = new Tire();
    
    void run(){
        frontLeftTire.roll();
        frontRightTire.roll();
        backLeftTire.roll();
        backRightTire.roll();
    }
}

이중 앞왼쪽 바퀴와 뒤오른쪽 바퀴를 각각 자식 클래스인 한국타이어와 금호타이어로 교체를 하면

부모인 타이어에 자식 클래스인 한국타이어와 금호타이어가 들어가게 된다.

Car myCar = new Car();
myCar.frontLeftTire = new HankookTire();
myCar.backRightTire = new KumhoTire();
myCar.run();

또한 run메소드를 통해 돌아가는 roll메소드 또한 자식 클래스에 오버라이딩 되어 있는 메소드가 있어 한국타이어와 금호타이어를 낀 부분은 부모와 다른 자식 메소드를 호출해 다른 성능을 내게 된다. 

 

 

 


매개 변수의 다형성

자동 타입 변환은 메소드를 호출할 때도 많이 발생한다.

메소드를 호출할때 매개 변수와 동일한 매개값을 지정하는 것이 정석이지만, 매개값을 다양화하기 위해 매개 변수에 자식 객체를 지정할 수도 있다.

이를 통해 매개 변수가 클래스 타입으로 지정되어 있는 경우, 해당 클래스의 객체 뿐만 아니라 자식 객체까지고 매개값으로 사용할 수 있음을 알게된다. 따라서 부모 클래스 타입으로 지정해놓고 어떤 자식 객체를 사용하느냐에 따라 실행결과가 달라진다. 자식 객체가 부모의 메소드를 오버라이딩 했다면 메소드 내부에서 자식이 오버라이딩한 메소드를 호출함으로써 메소드의 실행결과가 달라지는 것이다. 

부모 클래스 Vehicle run()
자식 클래스 1 Bus run() 오버라이딩
자식 클래스 2 Taxi run() 오버라이딩

부모클래스

public class Vehicle {
	public void run(){
    	System.out.println("차량이 달립니다.");
    }
}

자식클래스 (예시하나만)

public class Bus extends Vehicle {
	@Override
    public void run(){
    	System.out.println("버스가 달립니다");
    }
}

Vehicle을 이용하는 클래스

public class Driver{
    public void drive(Vehicle vehicle){
        vehicle.run();
    }
}

실행 클래스

public class DriverExample{
	public static void main(String[] args){
    	Driver driver  = new Driver();
        
        Vehicle vehicle = new Vehicle();
        Bus bus = new Bus();
        Taxi taxi = new Taxi();
        
        driver.drive(vehicle); 
        driver.drive(bus);	// 자동변환 자식메소드인 bus의 run실행
        driver.drive(taxi);	// 자동변환 자식메소드인 taxi의 run실행
    }
}
// 차량이 달립니다
// 버스가 달립니다
// 택시가 달립니다

 

 

 


강제 타입 변환

자동 타입 변환이 자식이 부모 타입이 되는 것이라면, 강제 타입 변환은 캐스팅 연산자를 사용하여 부모 타입을 자식 타입으로 변환하는 것을 말한다. 

모든 부모가 자식 타입으로 강제 변환 될 수 있는 것은 아니다. 자식 타입에서 부모타입으로 자동 변환이 되어 부모타입이 된 것을 다시 자식 타입으로 돌릴때 강제 타입 변환을 사용할 수 있다

자식타입 변수 = (자식타입) 부모타입;
Parent parent = new Child();	// 자동 타입 변환
Child child = (Child) parent;	// 강제 타입 변환

자식 타입이 부모 타입으로 바뀌면 부모의 메소드와 필드에만 접근할 수 있는데 이를 다시 자식 타입으로 변환하면 자식의 멤버를 사용할 수 있게 된다. 

 

 

 


객체 타입 확인

처음부터 부모타입으로 태어난 객체는 강제 타입 변환이 불가능하다. 그럼 태초에 부모타입의 변수가 부모 객체인지 자식 객체인지 확인 할 수 있는 방법이 있을까?

 

instanceof 연산자를 사용하면 된다. 

boolean result = 좌항(객체) instanceof 우항(타입)

instanceof를 기준으로 좌항의 객체가 우항의 타입의 인스턴스이면 true를 리턴하고 그렇지 않으면 false를 리턴한다.

 

이 연산자는 주로 매개값의 타입을 조사할 때 사용되며, 메소드 내에서 강제 타입 변환이 필요할 때는 이 연산자를 통해 매개값이 어떤 객체인지 확인하고 안전하게 강제 타입 변환을 해야한다. 

if(parent instanceof Child){
	Child child = (child) parent;
}

 

 

 

+ Recent posts