Programming/Java

[Java 자바] 8. 인터페이스 ② 사용 방법, 인터페이스 상속, 디폴트 메소드

erinh 2022. 8. 9. 20:50
반응형

8-4. 인터페이스 사용

인터페이스로 구현 객체를 사용하려면 인터페이스 변수를 선언하고 구현 객체를 대입해야 함

8-4-1. 추상 메소드 사용

구현 객체가 인터페이스 타입에 대입되면 인터페이스에 선언된 추상 메소드를 개발 코드에서 호출할 수 있음.
이 때, 메소드는 구현 객체에서 선언된 메소드가 자동으로 실행됨.

public class RemoteControlTest {
	public static void main(String[] args) {
    
		RemoteControl rc = new Television();
		rc.turnOn();	// TV가 켜집니다.
	}
}

8-4-2. 디폴트 메소드 사용

- 디폴트 메소드는 인터페이스에 선언되지만, 인터페이스를 통해 바로 사용은 불가능함
- 보통 인터페이스의 모든 구현 객체가 가지고 있는 기본 메소드로 사용되나, 구현 클래스에서 오버라이딩하여 사용도 가능함

// 아래와 같이 인터페이스명으로 바로 접근 불가능
RemoteControl.디폴트메소드명();

// 구현객체를 통해서만 호출 가능
RemoteControl rc = new Television();
rc.디폴트메소드명();

8-4-3. 정적 메소드 사용

- 인터페이스로 바로 호출 가능

RemoteControl.정적메소드명();

8-5. 타입 변환과 다형성

메소드에서 매개 변수를 인터페이스 타입으로 선언할 경우, 메소드 호출시 매개값으로 여러 가지 종류의 구현 객체를 줄 수 있음

8-5-1. 자동 타입 변환 (Promotion)

- 구현 객체가 인터페이스 타입으로 변환되는 것
- 인터페이스 구현 클래스를 상속하여 자식 클래스를 만들었다면 자식 객체 역시 인터페이스 타입으로 자동 타입 변환 가능

8-5-2. 필드의 다형성

- 필드 타입으로 인터페이스를 선언하면 필드값으로 다양한 인터페이스의 구현 객체들을 대입할 수 있음

//Tire interface를 구현한 HankookTire, KumhoTire 객체가 있다고 할 때.

//Car.java
public class Car {
  Tire frontLeftTire = new HankookTire();
  Tire frontRightTire = new HankookTire();
}

//CarTest.java
public class CarTest {
  public static void main(String[] args) {
    Car myCar = new Car();
    myCar.frontLeftTire = new KumhoTire();
  }
}

8-5-3. 인터페이스 배열로 구현 객체 관리

인터페이스 배열을 통한 관리도 가능

Tire[] tires = {
  new HankookTire();
  new HankookTire();
}

tires[1] = new KumhoTire();

8-5-4. 매개 변수의 다형성

메소드 호출시 매개변수에 인터페이스 타입으로 선언하고 호출할 때는 구현 객체를 대입하는 것도 가능 

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

//Vehicle.java
public interface Vehicle {
  public void run();
}

//Bus.java
public class Bus implements Vehicle {
  @Override
  public void run() {
    System.out.println("버스가 달립니다.");
  }
}

//Taxi.java
public class Taxi implements Vehicle {
  @Override
  public void run() {
    System.out.println("택시가 달립니다.");
  }
}

//DriverTest.java
public class DriverTest {
  public static void main(Strings[] args) {
    Driver drvier = new Driver();
    
    Bus bus = new Bus();
    Taxi taxi = new Taxi();
    
    driver.drive(bus);
    driver.drive(taxi);
  }
}

8-5-5. 강제 타입 변환 (Casting)

구현객체가 인터페이스 타입으로 자동변환될 경우, 구현객체 고유의 필드/메소드는 사용이 불가능함
- 이 경우, 강제 타입 변환을 해서 구현 클래스 타입으로 변환한 후 구현 클래스의 필드와 메소드를 사용할 수 있음

Vehicle vehicle = new Bus();
vehicle.bus고유메소드명();		// 사용불가

Bus bus = (Bus) vehicle;
bus.bus고유메소드명();		// 사용가능

8-5-6. 객체 타입 확인 (instanceof)

강제 타입 변환을 하기 전에는 매개값이 어떤 객체인지 Instanceof 연산자로 확인 후 안전하게 변환해야 함

8-6. 인터페이스 상속

인터페이스끼리 다른 인터페이스를 상속할 수 있으며, 다중 상속 역시 가능함
- 이 때, 이 하위인터페이스를 구현하는 클래스는 하위, 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 함

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

8-7. 디폴트 메소드와 인터페이스 확장

8-7-1. 디폴트 메소드의 필요성

- 기존 인터페이스를 확장해 새로운 기능을 추가하기 위해 필요
- 기존 인터페이스에 새로운 메소드를 추가할 경우, 이 인터페이스를 사용하고 있던 클래스는 해당 메소드가 없기 때문에 컴파일 에러 발생
- 추가한 메소드를 default 타입으로 선언할 경우, 기존 클래스에서는 오류 없이 사용 가능
- 신규로 해당 인터페이스를 사용하는 클래스들은 default메소드를 그대로 혹은 수정하여 사용 가능

8-7-2. 디폴트 메소드가 있는 인터페이스 상속

- 디폴트 메소드의 경우, 상속시에 그대로 사용하거나 오버라이딩할 수 있음
- 자식인터페이스에서 구현된 객체 역시도 부모인터페이스의 디폴트 메소드에 바로 접근 가능

반응형