08-2. 타입 변환과 다형성
by Hi.Claire📓 혼자 공부하는 자바 (신용권, 한빛미디어)
08. 인터페이스
08-2. 타입 변환과 다형성
다형성을 구현하기 위해서 메소드 재정의와 타입 변환이 필요하다.
상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술이라는 차이가 있지만, 둘 다 다형성을 구현하는 방법은 비슷하다.
인터페이스의 다형성
프로그램을 개발할 때 인터페이스를 사용해서 메소드를 호출하도록 코딩하면 구현 객체를 매우 손쉽고 빠르게 교체할 수 있다.
이처럼 프로그램 소스 코드는 변함이 없는데 구현 객체를 교체함으로써 프로그램의 실행 결과가 다양해지도록 한 것이 인터페이스의 다형성이다.
08-2-1. 자동 타입 변환
구현 객체가 인터페이스 타입으로 변환되는 것은 자동 타입 변환이다.
인터페이스 변수 = 구현객체;
인터페이스 구현 클래스를 상속해서 자식 클래스를 만들었다면 자식 객체 역시 인터페이스 타입으로 자동 타입 변환할 수 있다.
필드와 매개 변수를 인터페이스 타입으로 선언하면 다양한 구현 객체를 대입해서 실행결과를 다양하게 만들 수 있다.
08-2-2. 필드의 다형성
객체를 설계할 때 필드 타입으로 인터페이스를 선언하면 필드값으로 다양한 인터페이스 구현 객체를 대입할 수 있다.
자동 타입 변환이 일어나기 때문에 아무런 문제가 없다.
인터페이스 구현 객체는 인터페이스에 있는 메소드를 모두 가지고 있기 때문에 인터페이스와 사용 방법이 동일하다.
예시1. 인터페이스
public interface Tire {
public void roll();
}
예시2. 구현 클래스1 - HankookTire
public class HankookTire implements Tire {
@Override
public void roll() {
System.out.println("한국 타이어가 굴러갑니다.");
}
}
예시3. 구현 클래스2 - KumhoTire
public class KumhoTire implements Tire {
@Override
public void roll() {
System.out.println("금호 타이어가 굴러갑니다.");
}
}
예시4. 필드의 다형성
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();
}
}
예시5. 필드의 다형성 테스트
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car();
myCar.run();
myCar.frontLeftTire = new KumhoTire();
myCar.frontRightTire = new KumhoTire();
myCar.run();
}
}
한국 타이어가 굴러갑니다.
한국 타이어가 굴러갑니다.
한국 타이어가 굴러갑니다.
한국 타이어가 굴러갑니다.
금호 타이어가 굴러갑니다.
금호 타이어가 굴러갑니다.
한국 타이어가 굴러갑니다.
한국 타이어가 굴러갑니다.
08-2-3. 매개 변수의 다형성
메소드의 매개 변수 타입을 인터페이스로 선언하면 메소드 호출 시 매개값으로 여러 가지 종류의 구현 객체를 줄 수 있기 때문에 메소드의 실행결과가 다양하게 나온다. 이것이 인터페이스의 매개 변수의 다형성이다.
예시1. 매개 변수의 인터페이스화
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
예시2. 인터페이스
public interface Vehicle {
public void run();
}
예시3. 구현 클래스1 - Bus
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}
예시4. 구현 클래스2 - Taxi
public class Taxi implements Vehicle {
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
예시5. 매개 변수의 다형성 테스트
public class DriverExample {
public static void main(String[] args) {
Driver driver = new Driver();
driver.drive(new Bus());
driver.drive(new Taxi());
}
}
버스가 달립니다.
택시가 달립니다.
08-2-4. 강제 타입 변환
구현 객체가 인터페이스 타입으로 자동 타입 변환하면 인터페이스에 선언된 메소드만 사용 가능하다는 제약 사항이 따른다.
만약 구현 클래스에 선언된 필드와 메소드를 사용해야 할 경우에는 강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환한 다음, 구현 클래스의 필드와 메소드를 사용할 수 있다.
구현클래스 변수 = (구현클래스) 인터페이스변수;
예시1. 인터페이스
public interface Vehicle {
public void run();
}
예시2. 구현 클래스 - Bus
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
public void checkFare() {
System.out.println("승차 요금을 체크합니다.");
}
}
예시3. 강제 타입 변환
public class VehicleExample {
public static void main(String[] args) {
Vehicle vehicle = new Bus(); // 자동 타입 변환
vehicle.run();
//vehicle.checkFare();
Bus bus = (Bus) vehicle; // 강제 타입 변환
bus.run();
bus.checkFare();
}
}
버스가 달립니다.
버스가 달립니다.
승차 요금을 체크합니다.
08-2-5. 객체 타입 확인
강제 타입 변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서만 가능하다.
따라서 어떤 구현 객체가 변환되어 있는지 알 수 없는 상태에서 무작정 강제 타입 변환할 경우 ClassCastException이 발생할 수도 있다.
이때 instanceof 연산자를 사용하면 어떤 구현 객체가 인터페이스 타입으로 변환되었는지 확인할 수 있다.
예시1. 객체 타입 확인
public class Driver {
public void drive(Vehicle vehicle) {
if(vehicle instanceof Bus) {
Bus bus = (Bus) vehicle;
bus.checkFare();
}
vehicle.run();
}
}
예시2. 객체 타입 확인 테스트
public class DriverExample {
public static void main(String[] args) {
Driver driver = new Driver();
driver.drive(new Bus());
driver.drive(new Taxi());
}
}
승차 요금을 체크합니다.
버스가 달립니다.
택시가 달립니다.
08-2-6. 인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있다.
인터페이스는 클래스와 달리 다중 상속을 허용한다.
public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 { ... }
하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 한다.
그렇기 때문에 구현 클래스로부터 객체를 생성한 후에 하위 및 상위 인터페이스 타입으로 변환이 가능하다.
하위 인터페이스로 타입 변환이 되면 하위 및 상위 인터페이스에 선언된 모든 메소드를 사용할 수 있다.
상위 인터페이스로 타입 변환이 되면 상위 인터페이스에 선언된 메소드만 사용 가능하다.
예시1. 상위 인터페이스1
public interface InterfaceA {
public void methodA();
}
예시2. 상위 인터페이스2
public interface InterfaceB {
public void methodB();
}
예시3. 하위 인터페이스
public interface InterfaceC extends InterfaceA, InterfaceB {
public void methodC();
}
예시4. 하위 인터페이스 구현
public class ImplementationC implements InterfaceC {
public void methodA() {
System.out.println("ImplementationC-methodA() 실행");
}
public void methodB() {
System.out.println("ImplementationC-methodB() 실행");
}
public void methodC() {
System.out.println("ImplementationC-methodC() 실행");
}
}
예시5. 호출 가능 메소드
public class Example {
public static void main(String[] args) {
ImplementationC impl = new ImplementationC();
InterfaceA ia = impl;
ia.methodA();
System.out.println();
InterfaceB ib = impl;
ib.methodB();
System.out.println();
InterfaceC ic = impl;
ic.methodA();
ic.methodB();
ic.methodC();
}
}
ImplementationC-methodA() 실행
ImplementationC-methodB() 실행
ImplementationC-methodA() 실행
ImplementationC-methodB() 실행
ImplementationC-methodC() 실행
'☕️ Java > 혼자 공부하는 자바' 카테고리의 다른 글
08-1. 인터페이스 (0) | 2023.09.24 |
---|---|
07-3. 추상 클래스 (0) | 2023.09.24 |
07-2. 타입 변환과 다형성 (1) | 2023.09.23 |
07-1. 상속 (0) | 2023.09.18 |
06-6. 패키지와 접근 제한자 (0) | 2023.09.17 |
블로그의 정보
Claire's Study Note
Hi.Claire