Search

Chapter 8. 인터페이스

Created
2021/04/07 16:59
Tags

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
복사