희렌버핏
8장 인터페이스 본문
8.1 인터페이스의 역할
- 개발코드는 객체의 내부구조 알 필요 없고 인터페이스의 메소드만 알고 있으면 된다.
- 인터페이스 : 개발코드와 객체가 서로 통신하는 접점
- 개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해질 수 있다. (다형성)
- 개발 코드가 객체에 종속되지 않게 해서 객체를 교체할 수 있도록 하는 역할을 한다.
8.2 인터페이스 선언
8.2.1 인터페이스 선언
- 인터페이스 이름 : 규칙에 따라 작성
- 첫자는 대문자
- 숫자로 시작하면 안되고, '$'와 '_'만 됨
- 다른 단어 결합하면 대문자로 변경
- 소스 파일 생성
- 인터페이스 이름과 대소문자가 동일한 소스 파일 생성 (인터페이스명.java)
- 인터페이스 선언
[public] interface 인터페이스명 {...}
- 인터페이스 구성 멤버
- 상수 / 추상 메소드 / 디폴트 메소드 / 정적 메소드
interface 인터페이스명 {
타입 상수명 = 값; //상수
타입 메소드명(매개변수,...); //추상 메소드
default 타입 메소드명(매개변수,...) {...} //디폴트 메소드
static 타입 메소드명(매개변수) {...} //정적 메소드
}
8.2.2 상수 필드 선언
- 인터페이스는 상수 필드만 선언 가능 (데이터 저장 안해서 데이터 저장할 인스턴스나 정적 필드 필요 없다.)
- 인터페이스에 선언된 필드는 모두 public static final의 특징을 가짐. (필드 선언 시 생략해도 컴파일 과정에서 자동으로 붙는다.)
- 상수명은 대문자로 시작 (서로 다른 단어 구성 연결은 '_'로)
- 선언과 동시에 초기값 지정 (블록 작성할 수 없어, static {}으로 초기화 할 수 없다)
8.2.3 추상 메소드 선언
- 인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행
- 인터페이스 메소드는 실행블록 없는 추상메소드로 선언 (추상 메소드 선언 없이 메소드 선언만 해도 컴파일러 과정에서 자동으로 abstract가 붙는다.)
8.2.4 디폴트 메소드 선언
default 리턴타입 메소드명(매개변수, ...) {
실행 스크립트
}
- 실행 블럭을 가지고 있는 메소드
- default 키워드를 반드시 붙여야 한다.
- 기본적으로 public 접근 제한을 가진다. 생략해도 컴파일 과정에서 자동으로 붙는다.
8.2.5 정적 메소드 선언
static 리턴타입 메소드명(매개변수, ...) {
}
8.3 인터페이스 구현
- 구현 객체 : 인터페이스의 추상메소드에 대한 실체를 가진 객체
- 구현 클래스 : 구현 객체를 생성하는 클래스
- 구현 클래스 선언
- 자신의 객체가 인터페이스 타입으로 사용할 수 있음 명시
public class 구현클래스명 implements 인터페이스명 {
//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
- 실체 메소드를 작성하는 방법
- 메소드 선언부가 명확히 일치 돼야함
- 인터페이스에 있는 모든 추상 메소드가 실체 메소드로 재정의 되어야 한다. (모든 메소드가 재정의 되지 않으면 추상클래스로 작성)
- 실체 메소드들은 반드시 public을 붙여준다. (인터페이스의 기본 접근제한자가 public이기 때문에 public보다 낮은 접근 제한으로 작성할 수 없다)
- @Override를 이용해서 컴파일러로 정확히 작성 됐는지를 점검.
- 인터페이스 변수와 구현 객체
- 인터페이스 변수 = 구현객체; (구현객체에는 인터페이스에서 implements한 클래스만 올 수 있다.)
8.3.2 익명 구현 객체
- 이름 없는 클래스를 만들어서 바로 객체를 생성한 후 인터페이스 변수에 대입할 수 있다.
- 명시적인 구현 클래스 작성을 생략하고 바로 구현 객체를 얻는 방법
- 이름이 없는 구현 클래스 선언과 동시에 객체를 생성
인터페이스 변수 = new 인터페이스( ) { //생성자 호출처럼 보이지만 중괄호 안처럼 클래스를 생성하겠다는 것.
// 중괄호 안에 선언된 기본 생성자를 호출해서 객체를 만들어 인터페이스 변수에 대입하겠다.
//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
};
* 인터페이스는 직접 객체를 생성할 수 없어 생성자가 없다. (인터페이스는 객체의 사용방법을 기술한 것이지 객체 자체를 만들기 위한 설계도는 아니다.)
- 인터페이스의 추상 메소드들을 모두 재정의하는 실체 메소드가 있어야 한다.
- 추가적으로 작성한 필드와 메소드는 익명 객체 안에서만 사용할 수 있다. 인터페이스 변수로 접근 불가. (인터페이스에 작성되어 있는게 아니기 때문에)
- 주로 사용되는 곳
- UI 프로그래밍(Swing, java Fx, Android)에서 이벤트를 처리하기 위해 주로 사용
- 임시 작업 스레드를 만들기 위해 사용
- 자바8부터 지원하는 람다식은 내부적으로 익명 구현 객체를 사용
- 익명 구현 객체도 클래스(바이트코드) 파일을 가지고 있다. (익명 구현객체를 작성하고 클래스 작성 없었는데도 파일을 내부적으로 생성함)
- 클래스 $번호.class 파일명으로 생성된다. (익명 구현 객체의 수에 맞게 번호가 올라간다.)
8.3.3 다중 인터페이스 구현 클래스
public class 구현클래스명 implements 인터페이스 A, 인터페이스 B {
//인터페이스 A와 B가 가지고 있는 모든 추상 메소드 재정의
}
8.4 인터페이스 사용
- 인터페이스에 구현 객체를 대입하는 방법
1. 필드 : RemoteControl rc = new Television( ); //구현 객체가 초기값으로 대입
2. 생성자 : 매개변수로 인터페이스 변수를 선언, 객체 생성할 때 객체 대입 가능, 인터페이스의 구현객체라면 얼마든지
MyClass(RemoteControl rc){
this.rc = rc;
}
3. 메소드 : 로컬 변수로 인터페이스 변수를 선언해서
void methodA() {
//로컬 변수
RemoteControl rc = new Audio();
}
void methodB(RemoteControl ro) {...} <= mc.methodB(new Audio());
8.4.1 추상 메소드 사용
RemoteControl rc = new Television( );
rc.turnOn(); => Television의 turnOn() 실행
rc.turnOff(); => Television의 turnOff() 실행
8.4.2 디폴트 메소드 사용
- 추상메소드와 차이점은 실행 블록은 직접 가지고 있다는 것
- 구현객체를 인터페이스 변수에 대입해야만 호출할 수 있다.
- 모든 구현 객체가 가지고 있는 기본 메소드로 사용한다. (필요에 따라 디폴트 메소드를 재정의해서 사용할 수 있다.)
8.4.3 정적 메소드 사용