이것이 자바다 Chapter08. 인터페이스
1절. 인터페이스의 역할
인터페이스 : 개발 코드와 객체가 서로 통신하는 접점이다.
개발 코드는 객체의 내부 구조를 알 필요가 없고 인터페이스의 메소드만 알고 있으면 된다.
인터페이스의 역할
- 개발 코드가 객체에 종속되지 않게 하여 객체를 교체할 수 있도록 하는 역할을 한다.
- 개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해질 수 있다(다형성).
2절. 인터페이스의 선언
- 인터페이스의 이름
자바 식별자 작성 규칙에 따라 작성
- 소스 파일 생성 : 인터페이스 이름과 대소문자가 동일한 소스 파일을 생성
- 인터페이스 선언
[접근 제한자] interface [인터페이스명] { ... }
- 인터페이스의 구성 멤버 : 상수/추상메소드/default타입 메소드/static타입 메소드
(인터페이스에 선언되는 모든 상수는 static final의 특성을 가진다!
/ 선언시 초기값을 설정해야 함.
상수 필드(Constant Field)
인터페이스는 객체 사용 설명서이므로 런타임 시 데이터를 저장할 수 있는 필드를 선언할 수 없다. 그러나 상수 필드는 선언이 가능하다. 상수는 인터페이스에 고정된 값으로 런타임 시에 데이터를 바꿀 수 없다. 상수를 선언할 때에는 반드시 초기값을 대입해야 한다.
추상 메소드(Abstract Method)
인터페이스의 메소드는 기본적으로 실행 블록이 없는 추상 메소드로 선언한다.
디폴드 메소드(Default Method)
디폴드 메소드는 인터페이스에 선언되지만 사실은 객체가 가지고 있는 인스턴스 메소드라고 생각해야 한다. 자바 8에서 디폴드 메소드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다.
[public] default 리턴타입 메소드면(매개변수, ...) {...}
- default를 반드시 붙여야 한다.
- 기본적으로 public 접근 제한을 가진다.
- 실행 블록을 가진다!
정적 메소드(Static Method)
자바 8에서 추가된 인터페이스의 새로운 멤버이다.
[public] static 리턴타입 메소드명(매개변수, ...) {...}
- 기본적으로 public 접근 제한을 가진다.
- 실행 블록을 가진다.
3절. 인터페이스 구현
구현 객체와 구현 클래스
- 인터페이스의 추상 메소드에 대한 실체 메소드를 가진 객체 = 구현 객체
- 구현 객체를 생성하는 클래스 = 구현 클래스
구현 클래스 선언
- 자신의 객체가 인터페이스 타입으로 사용할 수 있음을 implements 키워드로 명시
public class 구현클래스명 implements 인터페이스명 {
// 인터페이스에 선언된 추상 메소드의 실체 메소드 선언 및 실행블록 작성.
}
추상 메소드의 실체 메소드를 작성하는 방법
- 메소드의 선언부가 정확히 일치해야 한다.
- 인터페이스의 모든 추상 메소드를 재정의하는 실체 메소드를 작성해야 한다.
- public보다 더 낮은 접근 제한으로 작성할 수 없다.
- 이클립스의 자동 생성 기능을 이용할 수 있다.
- @Override 어노테이션을 이용해 정확히 재정의되었는지 컴파일러가 체크할 수 있다.
3절. 인터페이스 구현
인터페이스 변수와 구현 객체
인터페이스를 사용하지 않은 경우 : Television tv = new Television();
인터페이스를 사용한 경우
[인터페이스명] [변수] = 구현객체;
[인터페이스명] [변수];
[변수] = 구현객체;
=>
RemoteControl rc;
rc = new Television();
rc = new Audio();
익명 구현 객체
- 명시적인 구현 클래스 작성을 생략하고 바로 구현 객체를 얻는 방법
(이름이 없는 구현 클래스 선언과 동시에 객체를 생성한다)
[인터페이스] [변수] = new 인터페이스(){
//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
};
인터페이스의 추상 메소드들을 모두 재정의하는 실체 메소드가 있어야 한다.
추가적으로 필드와 메소드를 선언할 수 있지만 익명 객체 안에서만 사용 가능하고,
인터페이스 변수로 접근할 수 없다.
- 주로 사용되는 곳 : UI 프로그래밍(Swing, Android)에서 이벤트 처리를 위해 주로 사용.
임시 작업 스레드를 만들기 위해 사용.
자바8부터 지원하는 람다식은 내부적으로 익명 구현 객체를 사용.
- 익명 구현 객체도 클래스(바이트코드) 파일을 가지고 있다.
클래스$번호.class 파일명으로 생성된다.
(익명 구현 객체의 수에 맞게 번호가 올라간다)
다중 인터페이스 구현
public class 구현클래스명 implements 인터페이스 A, 인터페이스 B {
// 인터페이스 A에 선언된 추상 메소드의 실체 메소드 선언
// 인터페이스 B에 선언된 추상 메소드의 실체 메소드 선언
}
4절. 인터페이스 사용
인터페이스에 구현 객체를 대입하는 방법
public class MyClass {
//필드
RemoteControl rc = new Television();
★//생성자
MyClass(RemoteControl rc){
this.rc = rc;
}
//메소드
void methodA(){
//로컬 변수
RemoteControl rc = new Audio();
}
★void methodB(RemoteControl rc){...}
}
추상 메소드 사용
- 구현 객체가 인터페이스 타입에 대입되면 인터페이스에 선언된 추상 메소드를 개발 코드에서 호출할 수 있게 된다.
디폴트 메소드 사용
- 인터페이스만으로는 사용할 수 없다.
* 구현 객체가 인터페이스에 대입되어야 호출할 수 있는 인스턴스 메소드이다.
- 모든 구현 객체가 가지고 있는 기본 메소드로 사용한다.
* 필요에 따라 구현 클래스가 디폴트 메소드를 재정의해서 사용할 수 있다.
정적 메소드 사용
- 인터페이스로 바로 호출이 가능하다!
5절. 타입 변환과 다형성
다형성 복습
- 하나의 타입에 여러가지 객체를 대입해서 다양한 실행 결과를 얻는 성질.
- 다형성을 구현하는 기술
상속 또는 인터페이스의 자동 타입 변환(Promotion)
오버라이딩
-다형성의 효과 : 다양한 실행 결과 / 객체 부품화시켜 유지보수 용이
ex)
// A와 B 클래스에 정의된 method의 내용에 따라 실행 결과가 달라짐.
I i = new A();
i.method1();
i.method2();
I i = new B(); // i 수정
i.method1();
i.method2();
- 인터페이스는 매개변수 타입으로 자주 등장한다.
메소드 호출시 매개값으로 여러가지 종류의 구현 객체를 대입할 수 있어
메소드 실행 결과가 다양하게 나온다.
public void useRemoteControl( RemoteControl rc ){...}
useRemoteControl( new Television() );
useRemoteControl( new Audio()) ;
- 자동 타입 변환(Promotion)
인터페이스 변수 = 구현객체; // 변수를 구현객체 타입으로 자동 타입 변환
B b = new B();.
A a1 = b;
- 필드의 다형성
Car myCar = new Car();
myCar.frontLeftTire = new KumhoTire();
myCar.BackLeftTire = new HankookTire();
- 인터페이스 배열로 구현 객체 관리
Tire[] tires = {
new HankookTIre(), // 0번 배열
new HankookTIre(), // 1번 배열
new HankookTIre(), // 2번 배열
new HankookTIre(), // 3번 배열
};
tires[1] = new KumhoTire();
void run(){
for(Tire tire : trires) {
tire.roll();
}
}
- 매개변수의 다형성
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus); // bus타입 객체가 대입됨, bus객체의 run()메소드 실행.
- 강제 타입 변환(Casting)
인터페이스 타입으로 자동 타입 변환 후, 다시 구현 클래스 타입으로 변환
(구현 클래스 타입에 선언된 다른 멤버를 사용하기 위해 필요)
구현클래스 변수 = (구현클래스) 인터페이스변수; // 강지 타입 변환
A라는 인터페이스, B라는 클래스가 있을 때
A a = new B();
B b = (B) a; // 강제 타입 변환 가능
A a = new C();
B b = (B) a; // 원래 B타입으로 생성된 객체가 아니므로 컴파일 오류.
- 객체 타입 확인(instanceof 연산자)
public void method(Vehicle vehicle) {
if(vehicle instanceof Bus) { // vehicle 매개변수가 참조하는 객체가 Bus인지 조사.
Bus bus = (Bus) vehicle; // Bus 객체일 경우 강제 타입 변환 가능.
}
}
6절. 인터페이스 상속
인터페이스간에도 상속이 가능
public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 {...}
- 하위 인터페이스를 구현하는 클래스는 아래 메소드를 모두 재정의해야 한다.
1. 상위 인터페이스1의 추상 메소드
2. 상위 인터페이스2의 추상 메소드
3. 하위 인터페이스의 추상 메소드
- 인터페이스 자동 타입 변환
★ 해당 타입의 인터페이스에 선언된 메소드만 호출할 수 있다.
ex)
public interface A { public void methodA(); }
public interface B { public void methodB(); }
public clas XXX implements Interface C {
methodA(){...}
methodB(){...}
methodC(){...}
}
public class Exam {
public static void main(String[] args) {
XXX temp = new XXX();
A a = temp; // A인터페이스로 정의된 a는 methodA()만 사용 가능
B b = temp; // B인터페이스로 정의된 b는 methodB()만 사용 가능
C c = temp; // A,B인터페이스를 상속받는 C 클래스로 정의돈 c는
methodA(), methodB(), methodC() 사용 가능.
c.methodA(); c.methodB(); c.methodC();
}
}
7절. 디폴트 메소드와 인터페이스 확장
디폴트 메소드의 어색한 동거
- 인터페이스 개념에 맞지 않는 디폴트 메소드
인터페이스의 개념 :
* 객체 사용 방법(메소드 호출 방법)을 기술한 타입.
* 따라서 메소드 선언부만 있으면 된다.
실행 내용을 가지고 있는 디폴드 메소드(자바8부터 허용)
* 인터페이스에 선언은 되지만, 인터페이스만으로 사용 불가.
* 구현 객체의 인스턴스 메소드이다.
- 디폴트 메소드의 필요성
기존 메소드에 추상 메소드를 추가할 수 없다.
* 기존 인터페이스에 추상 메소드를 추가하면 기존 구현 클래스들이 모두 에러난다.
디폴트 메소드는 추상 메소드가 아니다.
* ★디폴트 메소드를 추가하더라도 기존 구현 클래스들은 문제 없이 사용할 수 있다.
* 디폴트 메소드를 재정의하는 새로운 구현 클래스를 만들 수 있다.
* 인터페이스에서와 달리 구현 클래스에는 default 키워드를 붙이지 않는다.
- 디폴트 메소드가 있는 인터페이스 상속
부모 인터페이스의 디폴트 메소드를 자식 인터페이스로 활용하는 방법
* 디폴트 메소드를 단순히 상속만 받는다.
* 디폴트 메소드를 재정의(Override)해서 실행 내용을 변경한다.
* ★디폴트 메소드를 추상 메소드로 재선언한다.