[Java] 7-2 타입 변환과 다형성

Woohyun Shin·2021년 7월 25일
0

Java

목록 보기
2/10

다형성이란 '사용법은 같지만 다양한 객체를 이용해서 다양한 실행결과가 나오도록 하는 성질'이다.

ex)타이어 사용법은 모두 같지만 자동차에 어떤 타이어(객체)를 사용하느냐에 따라 성능이 달라짐.

다형성을 구현하기 위해선 '메소드 재정의'와 '타입 변환'이 필요하다.

자동 타입 변환

타입 변환이란 타입을 다른 타입으로 변환하는 행위이다.

2장에서 기본 타입의 변환에 대해 학습했듯, 클래스도 마찬가지로 상속 관계에 있는 클래스 사이에서 변환이 발생할 수 있다.

자식은 부모 타입으로 '자동 타입 변환'이 가능하다.

자동 타입 변환(Promotion)이란 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말하는데, 이는 다음과 같은 조건에서 발생한다.

(부모타입) 변수 = (자식타입);

자동 타입 변환의 개념은 자식이 부모의 특징과 기능을 상속받았기 때문에 자식이 부모와 동일하게 취급될 수 있다는 것이다.

Animal(부모)와 Cat(자식)클래스가 상속관계에 있다고 가정하면, Cat 클래스로부터 Cat 객체를 생성하고 이것을 Animal 변수에 대입하면 자동 타입 변환이 일어난다.
ex) Cat cat = new Cat();
Animal animal=cat;(new Cat();)

위 그림과 같이 animal변수와 cat변수는 모두 Cat 객체를 참조하고 있다.

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

부모 타입으로 자동 타입 변환된 이후에는 비록 변수는 자식 객체를 참조하지만, 부모 클래스에 선언된 멤버(필드와 메소드)에만 접근이 가능하다.
But ! 예외적으로 메소드가 자식 클래스에서 재정의되었다면 자식 클래스의 메소드가 대신 호출됨.

package sec03.exam02;

public class Parent {
	
	public void method1() {
		System.out.println("Parent-method1()");
	}
	
	public void method2() {
		System.out.println("Parent-method2()");
	}
	
}
package sec03.exam02;

public class Child extends Parent{
	
	@Override //재정의
	public void method2() {
		System.out.println("Child-method2()");
	}
	
	public void method3() {
		System.out.println("Child-method3()");
	}

}
package sec03.exam02;

public class ChildExample {

	public static void main(String[] args) {
		// TODO 자동 생성된 메소드 스텁
		
		Child child = new Child();
		
		Parent parent=child; //자동 타입 변환
		
		parent.method1();
		parent.method2(); //재정의된 메소드가 호출됨
        //parent.method3(); (호출 불가능)
		
	}

}

Parent-method1()
Child-method2()

필드의 다형성

위에서 공부한 자동 타입 변환이 왜 필요할까?

필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 필드 사용 결과가 달라질 수 있기 때문이다.(필드의 다형성)

자동차를 구성하는 부품(객체)은 언제든지 교체될 수 있듯이 프로그램도 서로 연결되고 각자의 역할이 있는 수많은 객체들이 다른 객체로 교체될 수 있어야하기 때문이다.

1.자동차 클래스를 처음 설계할 때 사용한 타이어 객체는 언제든지 성능이 좋은 다른 타이어 객체로 교체할 수 있어야 한다.(타입 변환)
2.새로 교체되는 타이어 객체는 기존 타이어와 사용 방법은 동일하지만(상속) 실행결과는 더 우수하게 또는 다르게(재정의) 나와야 할 것이다.

위에 내용처럼 프로그램으로 이를 구현하기 위해선 '상속','재정의','타입 변환'을 이용해야 한다.

부모 클래스를 "상속"하는 자식 클래스는 부모가 갖고 있는 필드와 메소드를 가지고 있으니 사용 방법이 동일할 것이고, 자식 클래스는 부모의 메소드를 "재정의"해서 메소드의 실행 내용을 변경하여 더 우수한 실행결과를 나오게 할 수 있으며, 자식 타입을 부모 타입으로 "변환"할 수 있는데 이것이 다형성을 구현할 수 있는 기술적 조건 3가지라고 할 수 있다.

매개 변수의 다형성

자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.

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

class Driver{

	void drive(Vehicle vehicle){
    vehicle.run();
    }
    
}

위 코드와 같이 Driver 클래스에는 drive() 메소드가 정의되어 있는데 매개 변수는 Vehicle 타입이므로 drive()메소드를 정상적으로 호출한다면 ..

Driver driver = new Driver();
Vehicle vehicle = new Vehicle;
driver.drive(vehicle);

이런 방법으로 호출되어야 할 것이다.

Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus);

하지만 만약에 'Vehicle 타입의 매개 변수'가 아니라 'Vehicle의 자식 클래스'인 Bus객체를 drive() 메소드의 매개값으로 넘겨준다면, '자동 타입 변환'이 발생하게 된다. (Vehicle vehicle = bus;)

여기서 매우 중요한 것은 ★★매개 변수의 타입이 클래스인 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로 사용할 수 있다는 것이다.

즉, 자식 객체가 부모의 메소드를 재정의했다면 매개값으로 어떤 자식 객체가 제공되느냐에 따라 메소드 내부에서 재정의된 메소드를 호출함으로써 메소드의 실행결과는 다양해질 수 있다.

강제 타입 변환

강제 타입 변환(Casting)은 부모 타입을 자식 타입으로 변환하는 것을 말한다.

자식 타입이 부모 타입으로 자동 타입 변환되면, 부모에 선언된 필드와 메소드만 사용 가능하다는 제약이 생기지만 만약에 자식에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 다시 자식 타입으로 변환한 후 사용하면 된다.

자식 타입이 부모 타입으로 자동 타입 변환 후 다시 자식 타입으로 변환할 때만 강제 타입 변환을 사용할 수 있다.
(자식타입 변수 = (자식타입) 부모타입;)

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

객체 타입 확인

강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 다음과 같이 처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없다.

Parent parent = new Parent();
Child child = (Child)parent; //강제 타입 변환을 할 수 없음

따라서 부모 변수가 참조하는 객체가 부모인지 자식인지 확인해야할 필요가 있다.

객체가 어떤 클래스의 인스턴스인지 확인하기 위해 'instanceof 연산자'를 사용한다.
boolean result = 좌항(객체) instanceof 우항(타입)

연산자의 좌항에는 객체가 오고 우항에는 타입이 오는데, 좌항의 객체가 우항의 인스턴스라면, 즉 우항의 타입으로 객체가 생성되었다면 true를 리턴하고 그렇지 않으면 false를 리턴한다.

instanceof 연산자는 주로 매개값의 타입을 조사할 때 사용된다.

메소드 내에서 강제 타입 변환이 필요할 경우 반드시 매개값이 어떤 객체인지 연산자로 확인하고 안전하게 강제 타입 변환을 해야한다.

만약 타입을 확인하지 않고 강제 타입 변환을 시도한다면 ClassCastException이 발생할 수 있다.

profile
조급함보다는 꾸준하게

0개의 댓글