[Java] 8-1 인터페이스

Woohyun Shin·2021년 7월 27일
0

Java

목록 보기
4/10

인터페이스(Interface)는 개발 코드와 객체가 서로 통신하는 접점 역할을 한다.

개발 코드가 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출하여 리턴값을 얻는다.

따라서 개발 코드는 객체의 내부 구조를 알 필요가 없고 인터페이스의 메소드만 알고 있으면 된다.

개발 코드로 직접 객체의 메소드를 호출하면 되는데 왜 중간에 인터페이스를 둘까 ? 개발 코드를 수정하지 않고 사용하는 객체를 변경하기 위해서이다(코드 변경없이 실행 내용과 리턴값을 다양화할 수 있음).

인터페이스는 하나가 아닌 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하느냐에 따라 실행 내용과 리턴값이 다를 수 있다.

인터페이스 선언

인터페이스의 물리적 형태는 클래스와 동일하지만 선언은 interface 키워드를 사용한다.

인터페이스는 '상수 필드(static final)'와 추상 메소드만을 구성 멤버로 가지며, 객체로 생성할 수 없기 때문에 생성자를 가질 수 없다.

interface 인터페이스이름{
//상수
타입 상수이름 =;
//추상 메소드
타입 메소드이름(매개변수,...);

}

상수 필드 선언

인터페이스는 객체 사용법을 정의한 것으로 데이터를 저장할 수 없기 때문에 상수 필드만 선언할 수 있다.

따라서 인터페이스에 선언된 필드는 모두 public static final의 특성을 갖는다. (생략하더라도 컴파일 과정에서 자동으로 붙음)

인터페이스 상수는 반드시 선언과 동시에 초기값을 지정해야 한다.

package sec03.exam02;

public interface RemoteControl {
	
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
	
}

추상 메소드 선언

인터페이스로 호출된 메소드는 객체에서 실행되므로 추상 메소드로 선언한다.

추상 메소드는 리턴 타입, 메소드 이름, 매개 변수만 기술되고 중괄호 {}를 붙이지 않는 메소드를 말한다.

인터페이스에 선언된 추상 메소드는 모두 public abstract 특성을 갖기 때문에 생략하더라도 컴파일 과정에서 자동으로 붙는다.

package sec03.exam02;

public interface RemoteControl {
	//상수
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
	
	//추상 메소드
	public void turnOn();
	public void turnOff();
	public void setVolume(int volume); //메소드 선언부만 작성
	
}

인터페이스 구현

개발 코드가 인터페이스 메소드를 호출하면 인터페이스가 객체의 메소드를 호출하기 때문에 객체는 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 갖고 있어야 한다.

이때 이러한 객체를 '구현(implement) 객체'라고 하고 구현 객체를 생성하는 클래스를 '구현 클래스'라고 한다.

구현 클래스

구현 클래스는 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 클래스 선언부에 implements 키워드를 추가하고 인터페이스 이름을 명시해야 한다.

public class 구현클래스이름 implements 인터페이스이름{
 //인터페이스에 선언된 추상 메소드의 실체 메소드 선언
}

그리고 인터페이스에 선언된 추상 메소드의 실체 메소드를 선언해야 한다.

package sec03.exam02;

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) { //인터페이스 상수를 이용해 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);
	}

}
package sec03.exam02;

public class Audio implements RemoteControl{
	//필드
	private int volume;
		
	//turnOn() 추상 메소드의 실체 메소드
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}
		
	//turnOff() 추상 메소드의 실체 메소드
	public void turnOff() {
		System.out.println("Audio를 끕니다.");
	}
		
	//setVolume() 추상 메소드의 실체 메소드
	public void setVolume(int volume) {
		if(volume>RemoteControl.MAX_VOLUME) { //인터페이스 상수를 이용해 volume 필드의 값 제한
			this.volume=RemoteControl.MAX_VOLUME;
		}
		else if(volume<RemoteControl.MIN_VOLUME) {
			this.volume=RemoteControl.MIN_VOLUME;
		}
		else {
			this.volume=volume;
		}
		System.out.println("현재 Audio 볼륨: "+this.volume);
	}
}

++인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제한으로 작성할 수 없다.(Public 생략 X)

★★인터페이스로 구현 객체를 사용하려면 다음과 같이 인터페이스 변수를 선언하고 구현 객체를 변수에 대입해야 한다.

인터페이스 변수는 참조 타입이므로 구현 객체의 번지를 저장한다.

package sec03.exam02;

public class RemoteControlExample {

	public static void main(String[] args) {
		// TODO 자동 생성된 메소드 스텁
		
		RemoteControl rc;
		rc=new Television();
		rc=new Audio();
		
	}

}

다중 인터페이스 구현 클래스

객체는 다음 그림과 같이 다수의 인터페이스 타입으로 사용할 수 있다.

다중 인터페이스를 구현할 경우, 구현 클래스는 모든 인터페이스의 추상 메소드에 대해 실체 메소드를 작성해야 한다.

package sec03.exam02;

public interface Searchable {

	void search(String url);
	
}
package sec03.exam02;

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) { //인터페이스 상수를 이용해 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+"을 검색합니다.");
	}
}
package sec03.exam02;

public class SmartTelevisionExample {

	public static void main(String[] args) {
		// TODO 자동 생성된 메소드 스텁
		
		SmartTelevision tv = new SmartTelevision();
		
		RemoteControl rc = tv;
		Searchable searchable = tv;

	}

}

SmartTelevision 클래스는 RemoteControl과 Searchable 인터페이스를 모두 구현하고 있기 때문에 SmartTelevision 객체를 RemoteControl 타입 변수와 Searchable 타입 변수에 각각 대입할 수 있다.

즉, 구현 객체가 인터페이스 변수에 대입될 수 있다.

인터페이스 사용

구현 객체가 인터페이스 변수에 대입된다는 사실을 알았으니 이번엔 인터페이스로 구현 객체를 사용하는 방법을 알아볼 것이다.

클래스를 선언할 때 인터페이스는 필드, 생성자 또는 메소드의 매개 변수, 생성자 또는 메소드의 로컬 변수로 선언될 수 있다.

구현 객체가 인터페이스 타입에 대입되면 인터페이스에 선언된 추상 메소드를 개발 코드에서 사용할 수 있게 된다.

package sec03.exam02;

public class MyClass {
	
	//필드
	RemoteControl rc = new Television();
	
	//생성자
	MyClass(){

	}
	
	MyClass(RemoteControl rc){
		this.rc=rc;
		rc.turnOn();
		rc.setVolume(5);
	}
	
	//메소드
	void methodA() {
		RemoteControl rc = new Audio();
		rc.turnOn();
		rc.setVolume(5);
	}
	
	void methodB(RemoteControl rc) {
		rc.turnOn();
		rc.setVolume(5);
	}

}
package sec03.exam02;

public class MyClassExample {

	public static void main(String[] args) {
		// TODO 자동 생성된 메소드 스텁
		
		System.out.println("1)------------------");
		
		MyClass myClass1 = new MyClass();
		myClass1.rc.turnOn();
		myClass1.rc.setVolume(5);
		
		System.out.println("2)------------------");
		
		MyClass myClass2 = new MyClass(new Audio());
		
		System.out.println("3)------------------");
		
		MyClass myClass3 = new MyClass();
		myClass3.methodA();
		
		System.out.println("4)------------------");
		
		MyClass myClass4 = new MyClass();
		myClass4.methodB(new Television());

	}

}

1)------------------
TV를 켭니다.
현재 TV 볼륨: 5
2)------------------
Audio를 켭니다.
현재 Audio 볼륨: 5
3)------------------
Audio를 켭니다.
현재 Audio 볼륨: 5
4)------------------
TV를 켭니다.
현재 TV 볼륨: 5

1. 인터페이스가 필드 타입으로 사용될 경우 : 필드에 구현 객체를 대입할 수 있다.

2. 인터페이스가 생성자의 매개 변수 타입으로 사용될 경우 : new 연산자로 객체를 생성할 때 구현 객체를 생성자의 매개값으로 대입할 수 있다.

3. 인터페이스가 로컬 변수 타입으로 사용될 경우 : 변수에 구현 객체를 대입할 수 있다.

4. 인터페이스가 메소드의 매개 변수 타입으로 사용될 경우 : 메소드 호출 시 구현 객체를 매개값으로 대입할 수 있다.

★★인터페이스 변수에 구현 객체가 대입이 된 후에는 재정의된 구현 객체의 메소드를 호출할 수 있다.

profile
조급함보다는 꾸준하게

0개의 댓글