인터페이스도 상속이 가능하며, 다중 상속을 허용한다.
public interface Child extends ParentA, ParentB {
...
}
자식 인터페이스의 구현 클래스는 자식 인터페이스와 부모 인터페이스의 모든 추상 메서드 를 재정의해야 한다.
이 구현 클래스는 자식 인터페이스 변수나 부모 인터페이스 변수에 대입될 수 있다.
Child child = new 구현클래스(); // 모든 추상메서드 호출가능
ParentA pA = new 구현클래스(); // ParentA의 추상메서드 호출 가능
ParentB pB = new 구현클래스(); // ParentB의 추상메서드 호출 가능
인터페이스 변수에 구현 클래스를 집어넣으면서 자동 타입 변환이 발생한다.
인터페이스명 변수 = new 구현클래스();
만약 구현 클래스의 자식 클래스가 있다면, 이 자식 클래스도 인터페이스 변수에 대입시켜 인터페이스 타입으로 자동 변환할 수 있다.
/* InterfaceA.java */
public interface InterfaceA { ... }
/* 구현클래스.java */
public class 구현클래스 implements interfaceA { ... }
/* Child.java */
public class Child extends 구현클래스 { ... }
/* 사용 */
InterfaceA interA;
interA = new 구현클래스();
interA = new Child();
인터페이스 타입을 구현 클래스 타입으로 강제 변환한다.
구현클래스 변수 = (구현클래스) 인터페이스변수;
구현 클래스를 인터페이스 변수에 대입해서 자동 변환 되었을때, 인터페이스에 선언되지 않은 메서드는 사용할 수가 없다. 이 메서드들을 사용하고 싶다면, 구현 클래스의 타입을 다시 구현클래스타입 으로 강제 변환해야 한다.
/* InterA.java */
public interface interA {
void methodA();
}
/* ImpleA.java */
public class ImpleA implements interA {
@Override
public void methodA() { ... }
public void methodB() { ... } // 추가 메서드
}
/* 자동 타입 변환 : methodA 호출 가능 */
InterA intera = new ImpleA();
intera.methodA();
/* 강제 타입 변환 : methodA, methodB 호출 가능 */
ImpleA implea = (ImpleA) intera;
implea.methodB();
인터페이스의 구현클래스A와 구현클래스B가 있을 때, 어떤 구현 클래스가 인터페이스 변수에 대입되었는지에 따라서 실행 코드의 결과가 달라질 수 있다.
/* Inter.java */
public interface Inter {
void method(); // 추상 메서드
}
/* ImpleA.java */
public class ImpleA implements Inter {
public method() {
System.out.println("A")
}
}
/* ImpleB.java */
public class ImpleB implements Inter {
public method() {
System.out.println("B")
}
}
/* 사용 */
Inter inter = new ImpleA();
inter.method(); // A 출력
Inter inter = new ImpleB();
inter.method(); // B 출력
매개변수 타입을 인터페이스로 선언하면, 메서드 호출 시 구현 클래스를 대입할 수 있다.
public class 클래스 {
void method(인터페이스타입 인터페이스변수) { ... }
}
인터페이스 CPU 와 구현 클래스 Intel, AMD 가 있고, 추상 메서드 powerOn 를 각각 재정의한다.
/* CPU.java */
public interface CPU {
void powerOn();
}
/* Intel.java */
public class Intel implements CPU {
@Override
public void powerOn() { ... }
}
/* AMD.java */
public class AMD implements CPU {
@Override
public void powerOn() { ... }
}
외부 클래스인 Desktop 의 start 메서드에서 powerOn 를 호출하는데, 이때 CPU 타입 매개변수를 이용해서 호출한다.
/* Desktop.java */
public class Desktop {
void start(CPU cpu) {
cpu.powerOn();
}
}
/* 실행 */
Desktop pc1 = new Desktop();
Intel intel = new Intel();
AMD amd = new AMD();
pc1.start(intel);
pc1.start(amd);
start 메서드의 매개변수 타입이 CPU 로 정해져있지만, 구현 클래스인 Intel , AMD 타입이 들어가서 자동 타입 변환이 발생한다.start 메서드가 실행될 때, powerOn() 메서드는 각 구현 클래스에서 Override 된 버전으로 실행된다.start 메서드에 매개변수로 어떤 구현 클래스가 들어가냐에 따라 실행 결과가 달라진다.start 메서드에서 받은 구현 클래스가 인터페이스 타입으로 자동 타입 변환 되었는데, 이 구현 클래스의 원래 타입을 확인하고 싶다면 instanceof 연산자를 사용한다.
public void start(CPU cpu) {
if(cpu instanceof Intel) {
Intel intel = (Intel) cpu;
// intel 변수 사용
}
}
구현 클래스가 Intel 타입일 경우, CPU 타입으로 자동 변환된 Intel 구현 클래스를 다시 Intel 타입으로 강제 변환 시켜준다.
위 코드는 아래와 같이 우측타입변수 를 이용해서 표현할 수도 있다.
public void start(CPU cpu) {
if(cpu instanceof Intel intel) {
// intel 변수 사용
}
}