인터페이스의 다형성
- 다형성을 구현하기 위해 필요한 2가지 : 메소드 재정의와 타입 변환
- 상속과 마찬가지로 인터페이스에서도 이 두 가지 기능이 제공됨
- 상속과 차이점 : 상속은 같은 종류의 하위 클래스 생성, 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술
인터페이스의 다형성이 필요한 이유 : 소스 코드의 변함 없이 구현 객체를 빠르고 쉽게 교체하기 위해서이다
이를 통해 구현 객체를 쉽게 교체하여 실행 결과가 다양해져 인터페이스의 다형성을 이루게 됨
자동 타입 변환
[인터페이스] [변수명] = 구현객체; // 자동 타입 변환
추가로, 인터페이스 구현 클래스를 상속한 자식 클래스가 만들어졌다면 그 자식 객체 역시 인터페이스 타입으로 자동 타입 변환 가능하다.
- 자동 타입 변환을 이용하여 필드나 매개변수의 다형성을 구현할 수 있다.
- 필드와 매개변수의 타입으로 인터페이스를 사용하면 다양한 구현 객체를 대입하여 실행 결과를 다양하게 할 수 있음
필드의 다형성
// 인터페이스
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();
}
}
함수 매개 인자의 다형성
// 인터페이스
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);
}
}
강제 타입 변환
구현클래스 객체가 인터페이스 타입으로 자동 변환하면 인터페이스에 선언된 추상 메소드만 사용 가능하다. 위 그림과 같이 Television 클래스가 RemoteControl 인터페이스의 구현 클래스이고 RemoteControl의 추상메소드 이외에 메소드를 선언했을 경우, 인터페이스 변수에 구현클래스 객체를 대입하게 되면 인터페이스 메소드에 없는 setTime, record 메소드는 사용하지 못하게 된다. 만약 이 상태에서 구현클래스의 메소드를 사용하고 싶다면 아래 그림과 같이 강제 타입 변환을 한 후에 사용할 수 있다. 강제 타입 변환의 조건은 아래서 설명한다.
객체 타입 확인
강제 타입 변환 시 무조건 강제 타입이 성공된다는 보장은 없다. 구현클래스 객체가 어떻게 변환되어 있는지 알 수 없는 상태에서 강제 타입 변환할 경우 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;
}
}
}
인터페이스 상속
클래스 상속의 경우에는 단일 상속만 가능하지만, 인터페이스의 경우는 다중 상속을 할 수 있다. 아래 그림과 같이 상속되었다고 한다면 interfaceC에는 methodC 메소드만 선언되어 있지만 실질적으로는 methodA, methodB가 있는 것이다.
위 그림의 인터페이스C를 구현한 클래스를 만들 경우에는 인터페이스C에 정의된 추상메소드 뿐만 아니라 상위 인터페이스A,B에 정의된 추상메소드도 재정의해야 한다. 또한, 인터페이스 C의 구현 클래스를 가지고 객체를 만들게 되면 당연히 인터페이스C 변수에 대입 시 자동 타입 변환이 되고, 인터페이스 A,B에 대해서도 자동 타입 변환이 가능하다.
여기서 주의할 점이 인터페이스A의 변수에 구현 클래스 객체를 받게 되면 당연히 인터페이스 A에 대한 메소드만 사용이 가능하고 인터페이스B의 변수에 받게될 때도 마찬가지이다. 하지만 인터페이스C는 A,B를 상속받았기 때문에 모든 메소드 사용이 가능하다.
정리하기
- 자동 타입 변환 : 구현 객체는 인터페이스 변수에 대입 시 자동 타입 변환된다.
- 다형성 : 인터페이스도 재정의와 타입 변환 기능을 제공하므로 다형성 구현이 가능하다.
- 강제 타입 변환 : 인터페이스에 대입된 구현클래스 객체를 다시 원래 타입으로 변환하는 것을 말한다.
- instanceof : 객체가 어떤 타입인지 조사할 때 사용한다. 강제 타입 변환하기 전에 if문의 조건문에 사용한다.
- 인터페이스 상속 : 인터페이스는 기존 클래스와 달리 다중 상속을 허용한다.
'Java > Java' 카테고리의 다른 글
[Java] 스레드(thread) (0) | 2022.12.08 |
---|---|
[Java] 예외 (1) | 2022.12.07 |
[Java] 인터페이스(Interface) (0) | 2022.12.05 |
[Java] 추상 클래스, 메소드 (0) | 2022.12.02 |
[Java]타입 변환과 다형성 (0) | 2022.11.30 |
댓글