1. 인터페이스의 역할
•
객체의 사용 방법을 정의한 타입 → 다형성을 구현하는 역할
•
자바 8 람다식 : 함수적 인터페이스의 구현 객체를 생성.
•
개발 코드와 객체의 접점 역할
•
개발 코드를 수정하지 않고 사용하는 객체를 변경하여 실행 내용과 리턴값을 달리 할 수 있다.
2. 인터페이스 선언
2.1 인터페이스 선언
•
컴파일 과정은 클래스와 동일하지만 선언 방법은 다르다.
[ public ] interface 인터페이스명 {
}
Java
복사
•
인터페이스명은 클래스명 작성 방법과 동일.
•
멤버로 상수와 메소드만을 갖는다.
◦
인터페이스는 객체를 생성할 수 없으므로 생성자가 없다.
◦
추상 메소드 및 디폴트/정적 메소드 선언 가능
interface 인터페이스명 {
// 인터페이스 멤버
// 상수, 추상 메소드, 디폴트 메소드, 정적 메소드
타입 상수명 = 값;
타입 메소드명(매개변수,);
default 타입 메소드명(매개변수,){};
static 타입 메소드명(매개변수,);
}
Java
복사
•
상수 : 인터페이스에 고정된 값. 선언 시 초기화.
•
추상 메소드 : 실제 실행부는 객체에서 구현.
•
디폴트 메소드 : 인터페이스에서 선언하고 객체가 갖고있는 인스턴스 메소드. 확장해서 새로운 기능 추가.
•
정적 메소드 : 객체 없이 인터페이스 만으로 호출 가능.
2.2 상수 필드 선언
인터페이스는 데이터를 저장할 수 있는 인스턴스, 정적 필드를 선언할 수 없는 대신 상수를 선언할 수 있다.
•
클래스의 상수는 'public static final' 키워드를 사용하지만 인터페이스는 생략이 가능하다.
•
상수명은 모두 대문자를 사용하고 단어는 _ 로 구분한다.
•
static {} 블록으로 초기화 할 수 없기 때문에, 선언과 동시에 초기화를 한다.
2.3 추상 메소드 선언
인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행된다. 그렇기 때문에 인터페이스의 메소드는 추상 메소드로 선언한다.
•
인터페이스의 추상 메소드는 'public abstract' 키워드의 특성을 갖고 생략이 가능하다.
2.4 디폴트 메소드 선언
자바 8부터 추가된 멤버. 선언 시 리턴타입 앞에 'dafault' 키워드를 붙이고 실행 부분도 함께 작성한다.
•
'public'의 특성을 갖고 생략이 가능하다.
2.5 정적 메소드 선언
자바 8부터 추가된 멤버. 클래스의 적정 메소드 선언과 동일하다.
•
'public'의 특성을 갖고 생략이 가능하다.
3. 인터페이스 구현
개발 코드에서 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출한다.
•
객체는 인터페이스에 정의된 추상 메소드를 재정의해야한다.
•
이러한 객체를 인터페이스의 '구현 객체' 라고 하고 클래스는 '구현 클래스' 라고 한다.
3.1 구현 클래스
보통의 클래스와 동일하지만 선언부에 'implements' 키워드와 인터페이스명을 명시해야 한다.
public class 구현클래스명 implements 인터페이스명 {
}
Java
복사
•
인터페이스에 선언된 추상 메소드를 재정의 하는 실체 메소드를 선언한다.
•
인터페이스의 추상 메소드가 'public' 으로 선언되었기 때문에 실체 메소드 선언 시 'public' 보다 낮은 접근 지정자를 사용할 수 없다.
•
인터페이스의 추상 메소드에 대응하는 실체 메소드를 선언하지 않으면 구현 클래스는 추상 클래스가 된다.
◦
클래스 선언부에 'abstract' 키워드 추가.
new 연산자로 구현 객체를 생성할 수 있다.
•
인터페이스로 구현 객체를 사용하려면 인터페이스 타입 변수를 선언하고 구현 객체를 대입한다.
인터페이스 변수;
변수 = 구현객체;
인터페이스 변수 = 구현객체;
Java
복사
3.2 익명 구현 객체
일회성의 구현 객체를 사용하기 위해 소스 파일을 만들고 클래스를 선언하는 것은 비효율적이다.
•
소스 파일을 만들지 않고 구현 객체를 만들 수 있는 '익명 구현 객체'를 지원.
•
UI, 이벤트 처리, 임시 작업 스레드를 만들고 처리하기 위해서 익명 구현 객체를 사용한다.
인터페이스 변수 = new 인터페이스(){
// 인터페이스 추상 메소드의 실체 메소드 선언
};
Java
복사
•
new 연산자 뒤에 인터페이스() { } 안에서 클래스를 선언하고 해당 클래스의 객체를 생성한다.
◦
중괄호 안에는 인터페이스의 추상 메소드를 재정의한 실체 메소드 작성
◦
추가적인 필드와 메소드는 객체 안에서만 사용할 수 있다.
public class RemoteEx {
public static void main(String[] args){
Remote rc = new Remote() {
public void turnOn() {
...
}
}
}
}
Java
복사
•
익명 구현 객체가 포함된 클래스를 컴파일하면 '클래스$' 형식의 '.class' 파일이 생성된다.
◦
예 ) RemotEx$1.class
•
$뒤의 숫자는 익명 구현 객체의 수만큼 증가한다.
3.3 다중 인터페이스 구현 클래스
객체는 다수의 인터페이스 타입으로 사용할 수 있다.
•
두개의 인터페이스가 객체의 메소드를 호출할 수 있으려면, 구현 클래스는 모든 인터페이스를 구현해야 한다.
public class 구현클래스명 implements 인터페이스A, 인터페이스B {
// 인터페이스A,B 추상 메소드의 실체 메소드 선언
}
Java
복사
•
만약 하나라도 실체 메소드로 선언하지 않으면 추상 클래스로 선언해야 한다.
4. 인터페이스 사용
인터페이스로 구현 객체를 사용하려면 인터페이스 변수에 구현 객체를 대입한다.
•
개발 코드에서 인터페이스는 클래스의 변수, 생성자와 메소드의 매개변수 및 로컬변수로 선언 가능
public class MyClass {
RemoteEx re = new Television();
MyClass(RemoteEx re) {
this.re = re;
}
void methodA() {
RemoteEx re = new Audio();
}
void methodB(RemoteEx re) {
}
}
Java
복사
4.1 추상 메소드 사용
구현 객체가 인터페이스 변수에 대입되면 인터페이스에 선언된 추상 메소드를 개발 코드에서 호출할 수 있다.
•
인터페이스를 통해 구현 객체에서 재정의한 실체 메소드가 호출된다.
4.2 디폴트 메소드 사용
디폴트 메소드는 인터페이스에서 선언되지만 바로 사용할 수 없다.
•
구현 객체가 있어야만 사용할 수 있다.
•
모든 구현 객체가 갖고있는 기본 메소드
◦
필요에 따라서 구현 객체에서 디폴트 메소드를 재정의할 수 있다.
4.3 정적 메소드 사용
인터페이스의 정적 메소드는 인터페이스로 바로 호출이 가능하다.
•
구현 객체를 생성하지 않고 호출할 수 있다.
5. 타입 변환과 다형성
상속에서 부모 타입에 어떤 자식 객체를 대입하느냐에 따라서 다양한 결과를 얻을 수 있다.
•
인터페이스 타입에 어떤 구현 객체를 대입하느냐에 따라서 다양한 결과를 얻을 수 있다.
•
A 클래스에 문제가 발생 → 클래스 교체 → B 클래스의 메소드로 변경
◦
메소드명, 매개변수 모두 다름
◦
선언부가 완전 동일한 클래스 설계는 어려움
•
인터페이스를 선언하고 A, B 구현 클래스 선언 → 구현 객체 변경
•
인터페이스는 메소드의 매개변수로 자주 사용
5.1 자동 타입 변환
구현 객체가 인터페이스 타입으로 변환되는 것
•
구현 클래스를 상속받은 자식 클래스의 객체도 인터페이스 타입으로 자동 타입 변환 가능
5.2 필드의 다형성
인터페이스 타입 필드에 다양한 구현 객체를 대입함으로써 다른 실행 결과를 얻을 수 있다.
5.3 인터페이스 배열로 구현 객체 관리
배열의 각 항목으로 인터페이스 구현 객체를 대입하여 관리할 수 있다.
•
반복문 사용시 편리함
5.4 매개 변수의 다형성
메소드의 매개변수를 인터페이스 타입으로 선언하고 호출 시 구현 객체를 대입한다.
•
자동 타입 변환 → 다양한 실행 결과
5.5 강제 타입 변환
인터페이스 타입으로 자동 타입 변환이 발생하면 인터페이스에 선언된 메소드만 호출이 가능하다
•
구현 객체에서 새롭게 선언된 메소드 사용 불가
구현클래스 변수 = (구현클래스) 인터페이스변수;
Java
복사
•
강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환한 후, 구현 클래스의 필드와 메소드를 사용
5.6 객체 타입 확인
구현 객체가 인터페이스 타입으로 변환되어 있는 경우에만 강제 타입 변환이 가능하다.
•
어떤 구현 클래스 타입의 객체가 인터페이스 타입으로 변환되었는지 확인 필요
public class Driver {
public void drive(Vehicle vehicle) {
if ( vehicle instanceof Bus ) {
Bus bus = (Bus) vehicle;
bus.check();
}
vehicle.run();
}
}
Java
복사
6. 인터페이스 상속
인터페이스도 클래스와 마찬가지로 상위 인터페이스를 상속받을 수 있다.
public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 {
}
Java
복사
•
하위 인터페이스를 구현한 클래스는 하위 인터페이스 + 상위 인터페이스 추상 메소드를 재정의
◦
하위 인터페이스의 객체는 하위 인터페이스와 상위 인터페이스로 자동 타입 변환 가능
◦
하위 인터페이스로 자동 타입 변환 → 하위 및 상위 인터페이스의 메소드 사용 가능
◦
상위 인터페이스로 자동 타입 변환 → 상위 인터페이스의 메소드만 사용 가능
7. 디폴트 메소드와 인터페이스 확장
디폴트 메소드는 인터페이스에서 선언 및 정의하고 구현 객체에서 사용한다.
•
모든 구현 객체가 공유하는 기본 메소드
7.1 디폴트 메소드의 필요성
디폴트 메소드를 사용하는 가장 큰 이유는 기존 인터페이스를 확장하여 새로운 기능을 추가
•
기존 인터페이스에 추상 메소드 추가 → 기존 구현 객체는 추상 메소드를 재정의하지 않음
•
기존 인터페이스에 디폴트 메소드 추가 → 기존 구현 객체는 재정의할 필요 없음
•
기존 인터페이스에 디폴트 메소드 추가 → 새로운 구현 객채에서 재정의 가능
기존 인터페이스의 이름과 추상 메소드를 변경할 필요 없이 디폴트 메소드를 추가하여 기존 구현 클래스를 그대로 사용할 수 있으며 추가로 새로운 구현 클래스는 디폴트 메소드를 재정의하여 활용할 수 있다.
7.2 디폴트 메소드가 있는 인터페이스 상속
부모 인터페이스에 디폴트 메소드가 정의되어 있는경우 자식 인터페이스에서 활용하는 방법
•
디폴트 메소드 상속
•
디폴트 메소드 재정의
•
디폴트 메소드를 추상 메소드로 재선언
부모 인터페이스의 디폴트 메소드를 자식 인터페이스 클래스에서 추상 메소드로 재선언
public interface ParentInterface {
public void method1();
public default void method2() {
...
}
}
Java
복사
public interface ChildInterface extends ParentInterface {
public [abstract] void method2();
}
Java
복사
public class Example implements ChildInterface {
public void main(String[] args) {
ChildInterface ci = new ChildInterface() {
public void method1() {
...
}
public void method2() {
...
}
}
}
}
Java
복사
interface InterX {
abstract int operate(double a, double b);
}
class A implements InterX {
public int operate(double a, double b) {
return a + b;
}
}
class B implements InterX {
public int operate(double a, double b) {
return a * b;
}
}
class Application {
public static void main() {
InterX inter = B();
int result = inter.operate(1.0, 2.0);
//B a = B();
//int result = a.operateB(1.0, 2.0);
}
}
JavaScript
복사