다중 인터페이스 구현
구현 객체는 여러 개의 인터페이스를 implements 할 수 있습니다. 구현 객체가 인터페이스 A와 인터페이스 B를 구현하고 있다면, 각각의 인터페이스를 통해 구현 객체를 사용할 수 있습니다.
public class 구현클래스명 implements 인터페이스A, 인터페이스B {
// 모든 추상 메소드 재정의
}
인터페이스A 변수 = new 구현클래스명(...);
인터페이스B 변수 = new 구현클래스명(...);
이 때, 모든 추상 메소드는 구현 클래스에서 정의를 해야합니다.
인터페이스 상속
인터페이스도 다른 인터페이스를 상속할 수 있으며, 클래스와 달리 다중 상속을 허용합니다.
public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 { ... }
자식인터페이스의 구현 클래스는 자식 인터페이스의 메소드 뿐만 아니라 부모인터페이스의 모든 추상 메소드를 재정의해야 합니다.
자식인터페이스 변수 = new 구현클래스(...);
부모인터페이스1 변수 = new 구현클래스(...);
부모인터페이스2 변수 = new 구현클래스(...);
구현 객체가 자식 인터페이스 변수에 대입되면 자식 및 부모 인터페이스의 추상 메소드를 모두 호출 할 수 있지만
부모 인터페이스 변수에 대입되면 부모 인터페이스에 선언된 추상 메소드만 호출 가능합니다.
타입 변환
인터페이스의 타입 변환은 인터페이스와 구현 클래스 간에 발생합니다. 인터페이스 변수에 구현 객체를 대입하면 구현 객체는 인터페이스 타입으로 자동 타입 변환됩니다.
반대로 인터페이스 타입을 구현 클래스 타입으로 변환시키는 것은 강제 타입 변환이 필요합니다.
자동 타입 변환
저번 상속에서도 공부 했듯이 자동 타입 변환은 자동으로 타입이 변환 되는 것입니다.
인터페이스 변수 = 구현객체; // 자동 타입 변환이 일어난다
public interface A {}
public class B implements A {}
public class C implements A {}
public class D extends B {}
public class E extends C {}
B b = new B();
C c = new C();
D d = new D();
E e = new E();
A a; // 인터페이스 변수 선언
a = b; // A <- B
a = c; // A <- C
a = d; // A <- D
a = e; // A <- E
강제 타입 변환
강제 타입 변환은 캐스팅 기호를 사용해서 인터페이스 타입을 구현 클래스 타입으로 변환시키는 것을 말합니다.
구현클래스 변수 = (구현클래스) 인터페이스변수; // 강제 타입변환
강제 타입 변환이 필요한 이유를 쉽게 설명하기 위해 이것이 자바다 책에 있는 예시를 가져왔습니다.
- RemoteControl
- turnOn();
- turnOff();
- setVolume(int volume);
- Television은 RemoteControl을 implements 한 것
- turnOn();
- turnOff();
- setVolume(int volume);
- setTime(); // Television의 메소드
- record(); // Television의 메소드
RemoteControl rc = new Television();
rc.turnOn();
rc.turnOff();
rc.setVolume(5);
만약 rc가 Televison의 메소드를 사용하고 싶다면
Television tv = (Television) rc;
tv.turnOn();
tv.turnOff();
tv.setVolume(5);
tv.setTime(); // tv가 가지고 있는 메소드
tv.record(); // tv가 가지고 있는 메소드
이렇게 사용할 수 있습니다!!
다형성
다형성은 자바에서 아주 중요한 개념입니다. 다형성을 구현할 때 사용하는 것은 상속과 인터페이스가 존재합니다. 저번에는 상속으로 다형성을 구현하는 방법에 대해 공부해봤습니다. 이제 인터페이스로 다형성을 구현해보는 방법을 공부해 볼려고 합니다.
저번에도 공부했듯이 다형성은 메소드 재정의와 저동 타입 변환이 합해져서 이루어집니다.
필드의 다형성
interface Anima {
void move();
}
class Dog implements Animal {
@Override
public void move() {
System.out.println("개는 네발로 걷는다.");
}
}
class Cat implements Animal {
@Override
public void move() {
System.out.println("고양이는 조용하게 걷는다.");
}
}
public class Main {
public static void main(String[] args) {
Animal[] Animals = new Animal[2];
Animals[0] = new Dog();
Animals[1] = new Cat();
for (Animal animal : Animals) {
animal.move();
}
}
}
이렇게 필드를 다르게 함으로써 메소드의 실행결과가 달라집니다.
매개변수의 다형성
메소드 호출 시 매개값을 다양화하기 위해 상속에서는 매개변수 타입을 부모 타입으로 선언하고 호출할 때에는 다양한 자식 객체를 대입합니다.
public interface Vehicle {
void run();
}
public class Driver {
void drive(Vehicle vehicle) {
vehicle.run();
}
}
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus); // 자동 타입 변환 발생 -> 매개변수 다형성
객체 타입 확인
자바에서 객체 타입을 확인하기 위해서는 instanceof 연산자를 사용했는데, 인터페이스에서도 사용할 수 있습니다.
예를 들어 Vehicle 인터페이스 변수에 대입된 객체가 Bus인지 확인하는 코드는
if (vehicle instanceof Bus) {
Bus bus = (Bus) vehicle;
}
// 자바 12부터는
if(vehicle instanceof Bus bus) {}
봉인된 인터페이스
자바 15부터는 무분별한 자식 인터페이스 생성을 방지하기 위해 봉인된 인터페이스를 사용할 수 있습니다.
public sealed interface InterfaceA permits InterfaceB { ... }
InterfaceA의 자식 인터페이스는 InterfaceB만 가능합니다. sealed 키워드를 사용하면 permits 키워드 뒤에 상속 가능한 자식 인터페이스를 지정해야 합니다.
public non-sealed interface InterfaceB extends InterfaceA { ... }
non-sealed는 봉인을 해제한다는 뜻입니다. 따라서 InterfaceB는 다른 자식 인터페이스를 만들 수 있습니다.
public interface InterfaceC extends InterfaceB { ... }
출처
이것이 자바다
https://product.kyobobook.co.kr/detail/S000061695652
'JAVA 공부' 카테고리의 다른 글
중첩 선언과 익명 객체 (0) | 2023.08.20 |
---|---|
인터페이스에 대해(1) (0) | 2023.08.16 |
추상 클래스와 봉인된 클래스 (0) | 2023.08.14 |
상속에 대해(2) (0) | 2023.08.14 |
상속에 대해(1) (0) | 2023.08.13 |