본문 바로가기
Programing/JAVA (& 혼공자Java)

자바(Java) - 타입 변환과 다형성

by a.k.a DUKI 2020. 11. 17.
728x90
반응형

다형성을 구현하기 위해서는 메소드 재정의와 타입 변환이 필요하다. 인터페이스 역시 이 두가지 기능이 제공되므로 상속과 더불어 다형성을 구현하는데 많이 사용된다.

상속은 같은 종류의 하위 클래스를 만드는 기술이고,

인터페이스는 사용방법이 동일한 클래스를 만드는 기술 이다.

개념상 차이는 있지만 상속과 인터페이스 둘 다 다형성을 구현하는 방법은 비슷하다.

 

 

인터페이스의 다형성

인터페이스 사용 방법은 동일하지만 구현 객체를 교체하여 프로그램 실행 결과를 다양하게 할 수 있다.

혼공자 유툽 참고

자동 타입 변환 (promotion)

구현 객체가 인터페이스 타입으로 변환되는 것이다. 

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

인터페이스 변수 = 구현객체;
//구현객체가 인터페이스 타입으로 변환

혼공자 유툽 참고

필드의 다형성

다양항 메소드의 실행 결과를 얻을 수 있다.

혼공자 유툽 참고

예시1) 필드의 다형성

인터페이스

public interface Tire {
	public void roll();
}

구현 클래스

public class HankookTire implements Tire {

	// Tire 인터페이스 구현
	@Override
	public void roll() {
		System.out.println("한국 타이어가 굴러간다.");
	}
}

구현 클래스

public class KumhoTire implements Tire{
	
	// Tire 인터페이스 구현
	@Override
	public void roll() {
		System.out.println("금호 타이어가 굴러간다.");
	}
}

필드 다형성

public class Car {
	// 인터페이스 타입 필드 선언과 초기 구현 객체 대입
	Tire frontLeftTire = new HankookTire();
	Tire frontRightTire = new HankookTire();
	Tire backLeftTire = new HankookTire();
	Tire backRightTire = new HankookTire();

	// 인터페이스에서 설명된 roll()메소드 호출
	void run() {
		frontLeftTire.roll();
		frontRightTire.roll();
		backLeftTire.roll();
		backRightTire.roll();
	}
}

필드 다형성 테스트

public class CarEx {

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

}

 

매개변수의 다형성

매개 변수를 인터페이스 타입으로 선언하고 호출할 때에 구현 객체를 대입한다.

public interface Vehicle{
	public void run();
}
public class Driver{
	publici void drive(Vehicle vehicle){ //구현 객체
    	vehicle.run(); //구현 객체의 run()메소드 실행
    }
}

혼공자 유툽 참고

예시2) 필드의 다형성

매개 변수의 인터페이스화 

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

인터페이스

public interface Vehicle {
	public void run();
}

구현 클래스

public class Bus implements Vehicle{

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

}

구현 클래스

public class Taxi implements Vehicle{

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

}

매개 변수의 다형성 테스트

public class DriverEx {

	public static void main(String[] args) {
		Driver driver = new Driver();

		Bus bus = new Bus();
		Taxi taxi = new Taxi();

		driver.drive(bus);
		driver.drive(taxi);

		System.out.println("-----------");

		// 위에꺼 간결하게 표현
		driver.drive(new Bus());
		driver.drive(new Taxi());
	}

}

 

강제 타입 변환(casting)

구현 객체가 인터페이스 타입으로 자동 타입 변호나하면, 인터페이스에 선언된 메소드만 사용 가능하다는 제약이 있다.

하지만, 경우에 따라서 구현 클래스에 선언된 필드와 메소드를 사용해야 할 경우도 발생한다. 이때 강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환한 다음, 구현 클래스의 필드와 메소드를 사용 할 수 있다.

혼공자 유툽 참고
혼공자 유툽 참고

예시3) 강제 타입 변환

인터페이스 

public interface Vehicle {
	public void run();
}

구현 클래스

public class Bus implements Vehicle{

	@Override
	public void run() {
		System.out.println("버스가 달린다.");
	}
	
	public void checkFare() {
		System.out.println("승차 요금을 체크한다.");
	}
}

강제 타입 변환

public class VehicleEx {

	public static void main(String[] args) {
		Vehicle vehicle = new Bus();

		vehicle.run();

		Bus bus = (Bus) vehicle; // 강제 타입 변환

		bus.run();
		bus.checkFare(); // Bus클래스에는 checkFare()가 있음
	}

}

 

객체 타입 확인

어떤 구현 객체가 변환 되어 있는지 알 수 없는 상태에서 무작정 강제 타입 변환하는 경우 ClassCastException이 발생 할 수 있다.

상속에서 객체 타입을 확인하기 위해 instanceof 연산자를 이용했었다. instanceof연산자는 인터페이스 타입에서도 사용할 수 있다.

if(vehicle instanceof Bus){
	Bus bus = (Bus) vehicle;
}

 

예시4) 객체 타입 확인

인터페이스 

public interface Vehicle {
	public void run();
}

구현 클래스

public class Bus implements Vehicle{

	@Override
	public void run() {
		System.out.println("버스가 달린다.");
	}
	
	public void checkFare() {
		System.out.println("승차 요금을 체크한다.");
	}
}

구현 클래스

public class Taxi implements Vehicle{

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

}

객체 타입 확인

public class Driver {
	public void drive(Vehicle vehicle) {// Bus객체, Taxi객체
		if (vehicle instanceof Bus) { // vehicle 매개 변수가 참조하는 객체가 Bus인지 조사
			Bus bus = (Bus) vehicle; // BUs객체일 경우 안전하게 강제 타입 변환
			bus.checkFare(); // Bus타입으로 강제타입변환하는 이유
		}
		vehicle.run();
	}
}

객체 타입 확인

public class DriverEx {

	public static void main(String[] args) {
		Driver driver = new Driver();
		
		driver.drive(new Bus());
		driver.drive(new Taxi());
	}

}

 

 

인터페이스 상속

인터페이스는 클래스와 달리 다중 상속을 허용하며, 인터페이스도 다른 인터페이스를 상속할 수 있다.

public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2{ ... }

혼공자 유툽 참고

예시5) 인터페이스 상속

상위 인터페이스 

public interface InterfaceA {
	public void methodA();
}

상위 인터페이스 

public interface InterfaceB {
	public void methodB();
}

하위 인터페이스

public interface InterfaceC extends InterfaceA, InterfaceB{
	public void methodC();
}

하위 인터페이스 구현

public class ImplementationC implements InterfaceC {

	@Override
	public void methodA() {
		System.out.println("ImplementationC-methodA() 실행");
	}

	@Override
	public void methodB() {
		System.out.println("ImplementationC-methodB() 실행");
	}

	@Override
	public void methodC() {
		System.out.println("ImplementationC-methodC() 실행");
	}

}

호출 가능 메소드

public class Ex {

	public static void main(String[] args) {
		ImplementationC impl = new ImplementationC();

		InterfaceA ia = impl;
		ia.methodA();	//InterfaceA 변수는 methodA()만 호출 가능
		System.out.println();	

		InterfaceB ib = impl;
		ib.methodB(); 	//InterfaceB 변수는 methodB()만 호출 가능
		System.out.println();	

		InterfaceC ic = impl;
		//InterfaceC 변수는 methodA(), methodB(), methodC() 모두 호출 가능
		ic.methodA();
		ic.methodB();
		ic.methodC();
	}
}

 

 

 

※용어 정리

  • 자동 타입 변환: 구현 객체가 인터페이스 변수에 대입되는 것

  • 다형성: 상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술이라는 개념상의 차이는 있지만, 둘다 다형성을 구현하는 방법은 비슷하다. 모두 재정의와 타입 변환 기능을 제공하기 때문이다.

  • 강제 타입 변환: 인터페이스에 대입된 구현 객체를 다시 원래 구현 클래스 타입으로 변환하는 것

  • instanceof: 강제 타입 변환을 하기 전에 변환이 가능한지 조사할 때 사용. 상속에서는 자식 클래스 타입인지, 인터페이스에서는 구현 클래스 타입인지를 확인할 때 사용

  • 인터페이스 상속: 인터페이스는 다중 상속을 허용한다. extends 키워드 뒤에 상위 인터페이스가 올 수 있다.

 

본 내용은 #혼자공부하는자바 책을 참고해 공부하려 작성했습니다.

 

728x90
반응형

댓글