인터페이스
역할
- 객체의 사용 방법을 정의한 타입
- 객체의 교환성을 높여주기 때문에 다형성을 구현하는 매우 중요한 역할
- 개발 코드가 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드 호출 ⇒ 개발 코드는 객체의 내부 구조를 알 필요 없고, 인터페이스의 메소드만 알고 있으면 됨
- 개발 코드와 객체 사이에 인터페이스를 두는 이유 ⇒ 개발 코드를 수정하지 않고 사용하는 객체를 변경할 수 있도록 하기 위해
선언
- class 대신 interface 키워드 사용
- 상수와 메소드만을 갖는다
상수 필드
- 인터페이스는 객체 사용 설명서 ⇒ 런타임 시 데이터를 저장할 수 있는 필드를 선언할 수 없음
- 상수 필드는 선언 가능 ⇒ 반드시 초기값 설정
- public static final로 선언 ⇒ 생략하도 컴파일 과정에서 자동 생성
추상 메소드
- 객체가 가지고 있는 메소드를 설명한 것으로 호출할 때 어떤 매개값이 필요하고, 리턴 타입이 무엇 인지만 알려줌
- 리턴 타입, 메소드명, 매개 변수만 기술되고 중괄호를 붙이지 않은 메소드
- public abstract ⇒ 생략해도 컴파일 과정에서 자동 생성
- 실제 실행부는 객체(구현 객체)
디폴트 메소드
- 자바 8에서 추가된 새로운 멤버
- 클래스의 인스턴스 메소드와 형태 동일하지만 default 키워드가 리턴 타입 앞에 붙음
- 인터페이스에 선언되지만 사실은 객체(구현 객체)가 가지고 있는 인스턴스 메소드
- 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해
정적 메소드
- 객체가 없어도 인터페이스만으로 호출 가능
- 자바 8에서 추가된 인터페이스의 새로운 멤버
- 클래스의 정적 메소드와 동일한 형태
- public 특성
인터페이스 구현
- 구현 객체 : 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가진 객체
- 구현 클래스 : 구현 객체를 생성하는 클래스
구현 클래스
- 보통의 클래스와 동일. 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 선언부에 implements 키워드를 추가하고 인터페이스명 명시
- 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
- 인터페이스의 추상 메소드들에 대한 실체 메소드를 작성할 때 public 보다 낮은 접근 제한 작성 불가
- 실체 메소드를 구현 클래스가 작성하지 않으면 구현 클래스는 자동으로 추상 클래스 ⇒ abstract 키워드 추가
익명 구현 객체
- 소스 파일을 만들지 않고도 구현 객체를 만드는 방법
- UI 프로그래밍에서 이벤트를 처리하기 위해, 임시 작업 스레드를 만들기 위해 익명 구현 객체 사용
- 람다식 ⇒ 인터페이스의 익명 구현 객체 생성
// 익명 구현 객체를 생성해 인터페이스 변수에 대입하는 코드. 끝에 ; 반드시 붙여야 함
인터페이스 변수 = new 인터페이스() {
// 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
다중 인터페이스 구현 클래스
- 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 함
인터페이스 사용
- 인터페이스 변수 선언 ⇒ 구현 객체를 대입
- 인터페이스 변수는 참조 타입이기 때문에 구현 객체의 번지 저장
추상 메소드 사용
- 구현 객체가 인터페이스 타입에 대입되면 인터페이스에 선언된 추상 메소드를 개발 코드에서 호출할 수 있음
디폴트 메소드 사용
- 인터페이스에서 선언되지만 인터페이스에서 바로 사용할 수 없음
- 인스턴스 메소드이므로 구현 객체가 있어야 사용 가능
- 인터페이스의 모든 구현 객첵 가지고 있는 기본 메소드
- 디폴드 메소드의 내용이 맞지 않을 때 오버라이딩 할 수 있음
정적 메소드 사용
타입 변환과 다형성
- 인터페이스에서도 다형성 구현 ⇒ 상속보다 인터페이스를 통해 다형성 구현하는 경우가 더 많음
- 상속 : 같은 종류의 하위 클래스를 만드는 기술 / 인터페이스 : 사용 방법이 동일한 클래스를 만드는 기술 ⇒ 둘 다 다형성 구현
- 인터페이스를 사용해서 메소드를 호출 ⇒ 구현 객체를 교체하는 것은 매우 쉽고 빠름
- 인터페이스는 메소드의 매개 변수로 많이 등장 ⇒ 매개 변수로 여러 가지 구현 객체를 줄 수 있기 때문에 다양한 결과 ⇒ 인터페이스 매개 변수의 다형성
자동 타입 변환
- 구현 객체가 인터페이스 타입으로 변환되는 것은 자동 타입 변환에 해당
- 인터페이스 구현 클래스를 상속해서 자식 클래스를 만들면 자식 객체 역시 인터페이스 타입으로 자동 타입 변환 가능
- 자동 타입 변환을 이용하여 필드의 다형성, 매개 변수의 다형성 구현
필드의 다형성
- 필드 타입으로 인터페이스를 선언하게 되면 필드값으로 객체를 대입. 자동 타입 변환이 일어나기 때문에 문제 없음
인터페이스 배열로 구현 객체 관리
- 인터페이스로 각각 선언한 것을 배열로 한번에 관리
매개 변수의 다형성
- 매개 변수의 타입이 인터페이스일 경우, 어떠한 구현 객체도 매개값으로 사용할 수 있고, 어떤 구현 객체가 제공되느냐에 따라 메소드의 실행 결과 다양해짐
강제 타입 변환
- 구현 객체가 인터페이스 타입으로 자동 변환하면, 인터페이스에 선언된 메소드만 사용 가능
- 구현 클래스에 선언된 필드와 메소드를 사용해야 할 경우 강제 타입 변환을 해서 다시 구현 클래스 타입으로 변환한 다음 구현 클래스의 필드와 메소드 사용할 수 있음
객체 타입 확인
- 강제 타입 변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능
- instanceof 연산자를 사용해서 어떤 구현 객체가 인스턴스 타입으로 변환되었는지 확인
인터페이스 상속
- 클래스와 달리 다중 상속 허용
- 하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드 갖고 있어야 함
- 구현 클래스로부터 객체를 생성하고 나서 하위 및 상위 인터페이스 타입으로 변환 가능
- 하위 인터페이스로 타입 변환이 되면 상/하위 인터페이스에 선언된 모든 메소드 사용 가능
- 상위 인터페이스로 타입 변환되면 상위 인터페이스에 선언된 메소드만 사용 가능
디폴트 메소드와 인터페이스 확장
- 디폴드 메소드는 인터페이스에서 선언된 인스턴스 메소드 ⇒ 구현 객체가 있어야 사용 가능
디폴트 메소드 필요성
- 기존 인터페이스를 확장해서 새로운 기능 추가하기 위해
- 기존 인터페이스의 이름과 추상 메소드의 변경 없이 디폴트 메소드만 추가할 수 있음
- 이전에 개발한 구현 클래스를 그대로 사용할 수 있으면서 새롭게 개발하는 클래스는 디폴트 메소드를 활용할 수 있음
디폴트 메소드가 있는 인터페이스 상속
- 부모 인터페이스에 디폴트 메소드가 정의되어 있을 경우 자식 인터페이스에서 활용하는 방법
- 디폴트 메소드를 단순히 상속만 받음
- 디폴트 메소드를 재정의해서 실행 내용을 변경
- 디폴트 메소드를 추상 메소드로 재선언