Java 파트8-2. 타입 변환과 다형성

1. 인터페이스의 다형성


인터페이스 변수에 다른 구현 클래스 객체를 대입하여 프로그램의 실행 결과를 다양화 할 수 있다.

그림1

A라는 객체 대신에 B라는 구현클래스 객체를 인터페이스 변수에 대입해도 method 사용법을 수정할 필요가 없다.


2. 자동 타입 변환


구현클래스 객체와 구현클래스 객체의 자식 객체는 인터페이스 타입으로 자동 타입 변환된다.

그림2


3. 필드의 다형성


// 인터페이스
package sec07.exam02.pack1;

public interface Tire {
	public void roll();
}

// 타이어마다 인터페이스 구현 클래스
package sec07.exam02.pack1;

public class KumhoTire implements Tire{

	@Override
	public void roll() {
		System.out.println("금호 타이어가 굴러간다.");		
	}
	
}

package sec07.exam02.pack1;

public class HankookTire implements Tire{

	@Override
	public void roll() {
		System.out.println("한국 타이어가 굴러간다.");		
	}
	
}

// Car 클래스
package sec07.exam02.pack1;

public class Car {
    // 인터페이스 변수에 각 객체 대입
	Tire frontLeftTire = new HankookTire();
	Tire frontRightTire = new HankookTire();
	Tire backLeftTire = new HankookTire();
	Tire backRightTire = new HankookTire();
	
	void run() {
		frontLeftTire.roll();
		frontRightTire.roll();
		backLeftTire.roll();
		backRightTire.roll();
		}

}

// 여기까지 인터페이스와 인터페이스 구현 클래스 객체를 연결시켰다.



// 실행 메인 클래스
// 메인 클래스에서는 Car객체를 만들어 Car의 필드인 인터페이스 변수에
// 다른 구현 클래스 객체를 대입해 다형성을 보이도록 했다.
package sec07.exam02.pack1;

public class CarExam {

	public static void main(String[] args) {
		Car myCar = new Car();
		myCar.run();
		
		myCar.frontLeftTire = new KumhoTire();
		myCar.frontRightTire = new KumhoTire();
		myCar.run();

	}

}


4. 함수 매개 인자의 다형성


// 인터페이스
package sec07.exam03.pack1;

public interface Vehicle {
	public void run();	
}

// 인터페이스 구현
package sec07.exam03.pack1;

public class Bus implements Vehicle{

	@Override
	public void run() {
		System.out.println("버스가 달린다");		
	}

}

package sec07.exam03.pack1;

public class Texi implements Vehicle{

	@Override
	public void run() {
		System.out.println("택시가 달린다");		
	}

}

// 인터페이스 구현 클래스 객체를 매개 인자로 받을 메소드를 선언할 클래스
package sec07.exam03.pack1;

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

// 메인 실행 클래스
package sec07.exam03.pack1;

public class VehicleExam {

	public static void main(String[] args) {

        // 매개 인자로 구현 객체 클래스로 받은 메소드 있는 클래스 객체 선언
		Driver driver = new Driver();

        // 인터페이스 구현클래스 객체
		Bus bus = new Bus();
		Texi texi = new Texi();
		
        // 매개 변수에 다른 구현 객체 클래스를 넣어주면서 다형성
		driver.drive(bus);		
		driver.drive(texi);

	}

}


5. 강제 타입 변환


그림3

구현클래스 객체가 인터페이스 타입으로 자동 변환하면 인터페이스에 선언된 추상 메소드만 사용 가능하다. 위 그림과 같이 Television 클래스가 RemoteControl 인터페이스의 구현 클래스이고 RemoteControl의 추상메소드 이외에 메소드를 선언했을 경우, 인터페이스 변수에 구현클래스 객체를 대입하게 되면 인터페이스 메소드에 없는 setTime, record 메소드는 사용하지 못하게 된다. 만약 이 상태에서 구현클래스의 메소드를 사용하고 싶다면 아래 그림과 같이 강제 타입 변환을 한 후에 사용할 수 있다. 강제 타입 변환의 조건은 아래서 설명한다.

그림4


6. 객체 타입 확인


강제 타입 변환 시 무조건 강제 타입이 성공된다는 보장은 없다. 구현클래스 객체가 어떻게 변환되어 있는지 알 수 없는 상태에서 강제 타입 변환할 경우 ClassCastException이 발생한다.
강제 타입 변환의 조건은 부모 클래스 객체를 자식 클래스 객체로 강제 타입변환 했을 때의 조건과 같다. 즉, 인터페이스 변수의 강제 타입 변환은 인터페이스 변수에 구현 클래스 객체가 대입되어있는 상태에서 다시 해당 구현 클래스로 되돌릴 때만 사용이 가능한 것이다.

// vehicle이 인터페이스, Taxi가 구현 클래스라고 가정
Vehicle vehicle = new Taxi();
Bus bus = (Bus) vehicle; // classcastexecption 발생

public void drive(Vehicle vehicle){
    // 매개 인자로 어떤 구현 클래스가 들어올지 모르는데 Bus로 강제 타입 변환시
    // classcastexception이 발생할 수 있다.
    Bus bus = (Bus) vehicle; 
}

// instanceof 로 해결
public class Driver{
    public void drive(Vehicle vehicle){
        // 매개 인자로 들어온 vehicle이 Bus로 부터 만들어진 객체일경우
        if(vehicle instanceof Bus){
            Bus bus = (Bus) vehicle;
        }
    }
}


7. 인터페이스 상속


클래스 상속의 경우에는 단일 상속만 가능하지만, 인터페이스의 경우는 다중 상속을 할 수 있다. 아래 그림과 같이 상속되었다고 한다면 interfaceC에는 methodC 메소드만 선언되어 있지만 실질적으로는 methodA, methodB가 있는 것이다.

그림5

위 그림의 인터페이스C를 구현한 클래스를 만들 경우에는 인터페이스C에 정의된 추상메소드 뿐만 아니라 상위 인터페이스A,B에 정의된 추상메소드도 재정의해야 한다. 또한, 인터페이스 C의 구현 클래스를 가지고 객체를 만들게 되면 당연히 인터페이스C 변수에 대입 시 자동 타입 변환이 되고, 인터페이스 A,B에 대해서도 자동 타입 변환이 가능하다.
여기서 주의할 점이 인터페이스A의 변수에 구현 클래스 객체를 받게 되면 당연히 인터페이스 A에 대한 메소드만 사용이 가능하고 인터페이스B의 변수에 받게될 때도 마찬가지이다. 하지만 인터페이스C는 A,B를 상속받았기 때문에 모든 메소드 사용이 가능하다.

그림6


8. 정리하기


  • 자동 타입 변환 : 구현 객체는 인터페이스 변수에 대입 시 자동 타입 변환된다.
  • 다형성 : 인터페이스도 재정의와 타입 변환 기능을 제공하므로 다형성 구현이 가능하다.
  • 강제 타입 변환 : 인터페이스에 대입된 구현클래스 객체를 다시 원래 타입으로 변환하는 것을 말한다.
  • instanceof : 객체가 어떤 타입인지 조사할 때 사용한다. 강제 타입 변환하기 전에 if문의 조건문에 사용한다.
  • 인터페이스 상속 : 인터페이스는 기존 클래스와 달리 다중 상속을 허용한다.



© 2021. By Backtony