개발 코드가 인터페이스 메소드를 호출하면 인터페이스는 객체의 메소드를 호출한다.
객체는 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 한다. 이러한 객체를 인터페이스의 구현(implement
) 객체라고 하고, 구현 객체를 생성하는 클래스를 구현 클래스라고 한다.
implements
키워드를 추가하고 인터페이스명을 명시해야 한다.public class 구현클래스명 implements 인터페이스명 {
//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}
Television
(구현 클래스)public class Television implements RemoteControl {
//필드
private int volume;
//turnOn() 추상 메소드의 실체 메소드
public void turnOn() {
System.out.println("TV를 켭니다.");
}
//turnOff() 추상 메소드의 실체 메소드
public void turnOff() {
System.out.println("TV를 끕니다.");
}
//setVolume() 추상 메소드의 실체 메소드
public void setVolume(int volume) {
if (volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME
} else if (volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME
} else {
this.volume = volume;
}
System.out.println("현재 TV 볼륨: " + this.volume);
}
}
📌 주의 | 인터페이스의 모든 메소드는 기본적으로
public
접근 제한을 갖는다!
그렇기 때문에 구현 클래스에서 인터페이스의 추상 메소드들에 대한 실체 메소드를 작성할 때public
보다 더 낮은 접근 제한으로 작성할 수 없다.public
을 생략하게 되면 컴파일 에러가 발생하게 된다.
public abstract class Television implements RemoteControl {
public void turnOn() { ... }
public void turnOff() { ... }
//setVolume() 실체 메소드가 없다.
}
abstract
키워드를 추가해야 한다.구현 클래스가 작성되면 new
연산자로 객체를 생성할 수 있다.
인터페이스로 구현 객체를 사용하려면 다음과 같이 인터페이스 변수를 선언하고 구현 객체를 대입해야 한다.
인터페이스 변수는 참조 타입이기 때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장해야 한다.
인터페이스 변수;
변수 = 구현 객체;
인터페이스 변수 = 구현 객체
RemoteControl
인터페이스 구현 객체인 Television
과 Audio
를 사용하려면 다음과 같이 RemoteControl
타입 변수 rc
를 선언하고 구현 객체를 대입해야 한다.
public class RemoteControlExample {
public static void main(String[] args) {
RemoteControl rc;
rc = new Television();
rc = new Audio();
}
}
구현 클래스를 만들어 사용하는 방법은 일반적이고, 클래스를 재사용할 수 있기 때문에 편리하다.
하지만 일회성의 구현 객체를 만들기 위해 소스 파일을 만들고 클래스를 선언하는 것은 비효율적이다.
그래서 자바는 익명 구현 객체를 통해 소스 파일을 만들지 않고도 구현 객체를 만드는 방법을 제공한다.
다음은 익명 구현 객체를 생성해서 인터페이스 변수에 대입하는 코드이다.
작성 시 주의할 점은 하나의 실행문이므로 끝에는 세미콜론(;
)을 반드시 붙여야 한다.
인터페이스 변수 = new 인터페이스() {
//인터페이스에 선언된 추상 메소드의 실체 메소드 선언
};
new
연산자 뒤에는 클래스 이름이 와야하는데 이름이 없다.인터페이스() {}
는 인터페이스를 구현해서 중괄호 {}
와 같이 클래스를 선언하라는 뜻이다.new
연산자는 이렇게 선언된 클래스를 객체로 생성한다.{}
에는 인터페이스에 선언된 모든 추상 메소드들의 실체 메소드를 작성해야 한다. 그렇지 않으면 컴파일 에러가 발생한다.RemoteControl
의 익명 구현 객체 만들기public class RemoteControlExample {
public static void main(String[] args) {
RemoteControl rc = new RemoteControl() {
public void turnOn() { /*실행문*/ }
public void turnOff() { /*실행문*/ }
public void setVolume(int volume) { /*실행문*/ }
};
}
}
모든 객체는 클래스로부터 생성되듯이, 익명 구현 객체도 예외는 아니다.
RemoteControlExample.java
를 컴파일하면 자바 컴파일러에 의해 자동으로 다음과 같은 클래스 파일이 만들어진다.
RemoteControlExample$1.java
RemoteControlExample
이름 뒤에 $
가 붙고 1번부터 시작하는 생성 번호가 붙는다.
객체는 다수의 인터페이스 타입으로 사용할 수 있다.
인터페이스 A
와 인터페이스 B
가 객체의 메소드를 호출할 수 있으려면 객체는 이 두 인터페이스를 모두 구현해야 한다.
따라서 구현 클래스는 다음과 같이 작성되어야 한다.
public class 구현클래스명 impllements 인터페이스A, 인터페이스B {
//인터페이스 A에 선언된 추상 메소드의 실제 메소드 선언
//인터페이스 B에 선언된 추상 메소드의 실제 메소드 선언
}
다중 인터페이스를 구현할 경우, 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 한다.
만약 하나라도 없으면 추상 클래스로 선언해야 한다.
Searchable
(인터페이스)public interface Searchable {
void search(String url);
}
SmartTelevision
(RemoteControl
과 Searchable
인터페이스를 모두 구현한 다중 인터페이스 구현 클래스)public class SmartTelevision implements RemoteControl, Searchable {
private int volume;
//RemoteControl의 추상 메소드에 대한 실체 메소드
public void turnOn() {
System.out.println("TV를 켭니다.");
}
public void turnOff() {
System.out.println("TV를 끕니다.");
}
public void setVolume(int volume) {
if (volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME
} else if (volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME
} else {
this.volume = volume;
}
System.out.println("현재 TV 볼륨: " + this.volume);
}
//Searchable의 추상 메소드에 대한 실체 메소드
public void search(String url) {
System.out.println(url + "을 검색합니다.");
}
}