본문 바로가기
JAVA

인터페이스

by 요리하다그만둠 2022. 5. 24.
인터페이스 변수 = new 인터페이스() {

              // 인터페이스에 선언된 추상 메소드의 실체 메소드 선언

};

JAVA에서의 interface는 객체의 사용 방법을 정의한 타입입니다. 

인터페이스는 객체의 교환성을 높여주기 때문에 다향성을 구현하는 매우 중요한 역할을 합니다.

 

인터페이스는 개발 코드와 객체가 서로 통신하는 접정 역할을 하는데 개발 코드가 인터페이스의 메서드를

호출하면 인터페이스는 객체의 메서드를 호출시켜준다. 그렇기 때문에 개발 코드는 객체의 내부 구조를 알 필요가 없고

인터페이스의 메서드만 알고 있으면 됩니다.

 

또한 개발 코드가 직접 객체의 메서드를 호출하면 간단한데 왜 중간에 인터페이스를 사용하는 이유는

개발 코드를 수정하지 않고 사용하는 객체를 변경할 수 있도록 하기 위해서입니다.

 

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

다를 수 있습니다. 따라 개발 코드 측면에서는 코드 변경 없이 실행 내용과 리턴 값이 다양화할 수 있다는 장점을 가지게 됩니다.

 

선언은 class 키워드 대신에 interface 키워드를 사용하고 [public] interface 인터페이스명 {...} 으로 작성합니다.

 

 

인스턴스 메서드는 사용할 수 없다.

 

인터페이스는 상수 + 추상 메서드 들로 이루어져 있습니다. 인터 페이스는 public 접근 제한자만 허용하고

보통 class에서 접근자 무표기하면 default 타입으로 적용되지만 인터페이스에서는 public로 저장됩니다.

 

- 상수 필드

: 인터페이스는 객체 사용 설명서이므로 런타임 시 데이터를 저장할 수 있는 필드를 선언할 수 없는데 상수 필드는 선언이 가능합니다. 상수는 인터페이스에서 고정된 값으로 런타입시 데이터 변경이 불가능합니다. 선언 시 반드시 초기값을 넣어야 합니다. String name; (x) String name = "홍길동"; (o)

 

- 추상 메소드 (지시 -> 명령)

추상 소드는 객체가 가지고 있는 메서드를 설명한 것으로 호출할 때 어떤 매개 값이 필요하고, 리턴 타입이 무엇인지만 알려줍니다. 실제 실행부는 객체 (구현 객체)가 가지고 있습니다.

예제)

// 인터페이스는 데이터를 저장할수 없기 떄문에 
// 대이터를 저장할 필드를 선언할수없다.
// 대신 상수 필드만 선언할수 있다. 
// 상수는 public static final로 선언
public interface RemoteControl {
	// 인터페이스 상수는 static{}블록을  초기화 못하기 때문에
	// 선언가 동시에 초기값 선언.
	
	//상수
	public int MAX_VOLUME = 10;
	public int MIN_VOLUME = 0;
	
	// 추상 메서드
	public void turnOn();
	public void turnOff();
	public void setVolume(int volume);
	// 메서드 선언부만 작성(추상 클레스 특징)
	
	// default Method - 실행 내용까지 저장
	// 자바8에서 추가된 인터페이스의 새로운 맴버
	// default Method는 public의 특징을 갖는다.
	default void setMute(boolean mute) {
		if(mute) {
			System.out.println("무음 처리합니다.");
		}else {
			System.out.println("무음 해제합니다.");
		}
	}
	// 정적 메서드
	// 형태는 클레스 메서드와 동일
	// 정적 메서드도 public 특징을 갖게됨
	static void chanegeBattery() {
		System.out.println("건전지를 교환합니다.");
	}
}

구현부- Television

package book;

// 구현부 implements
public class Television implements RemoteControl {
	
	// 필드 선언
	private int volume;
	
	// RemoteControl 에는 추상메소드가 3개가 있기때문에
	// 이 메서드들의 대한 실체 메서드를 가지고있어야함
	@Override
	public void turnOn() {
		System.out.println("Tv를 켭니다.");
		
	}

	@Override
	public void turnOff() {
		System.out.println("Tv를 끕니다.");
		
	}

	@Override
	// 인터페이스 상수를 이용해서 volume필드의 값을 제한함
	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 볼륨 : "+volume);
	}

}

구현부-Audio

package book;

// 구현부 implements
public class Audio implements RemoteControl {
	
	// 필드 선언
	private int volume;
	
	// RemoteControl 에는 추상메소드가 3개가 있기때문에
	// 이 메서드들의 대한 실체 메서드를 가지고있어야함
	@Override
	public void turnOn() {
		System.out.println("Audio 를 켭니다.");
		 
	}

	@Override
	public void turnOff() {
		System.out.println("Audio 를 끕니다.");
		
	}

	@Override
	// 인터페이스 상수를 이용해서 volume필드의 값을 제한함
	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("현재 Audio 볼륨 : "+volume);
	}

}

구현 클래스에서 인터페이스의 추상 메소드들에 대한 실체 메서드를 작성할 때 주의할 점은 인터 페이스의 모든 메서드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제 한으로 작성할 수 없습니다.

 

public을 생략하면 “Cannot reduce the visibility of the inherited method"라는 컴파일 에러가 납니다.

만약 인터페이스에 선언된 추상 메소드에 대응하는 실제 메서드를 구현 클래스가 작성하지 않으면 구현 클래스는 지동적으로 추상 클래스가 되고. 그렇기 때 문에 클래스 선언부에 abstract 카워드를 추가해야 합니다.

public abstract class Television implements RemoteControl {
	public void turnOn() {...}
    public void turnOff() {...} setVolume() 실체 메소드가 없다.
    						(일부만 구현)
    	
    }

구현 클레스까지 작성이 끝나면 new 연산자로 객체를 생성할 수 있다. 문제는 어떤 타입의 변수에 대입하냐인데

Television tv new Television(); (x)
// Television 객체를 생성하고 Television 변수에 대입한다고 인터페이스를 사용하는 것이 아닙니다.

인터페이스 변수;            인터페이스 변수 = 구현 객체;

변수 = 구현 객체;

보통은 구현 클래스를 만들어 사용하는 것이 일반직이고 클래스를 재사용할 수 있기 때문에 편리하지만

일회성의 구현 객체를 만들기 위해 소스 파일을 만들고 클래스를 선언하는 것은 비효율적이다. 자바는 소스 파일을 만들지 않고도 구현 객체를 만들 수 있는 방법이 있는데 그게 익명 구현 객체이다.

 

밑에는 인터페이스 구현 객체를 생성해서 인터페이스 변수에 대입하는 코드인데 주의점이 실행문 끝에는 꼭 세미콜론을 사용해야 한다 *(;)

 

- 다중 인터페이스 구현 클레스

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

인터페이스 A와 인터페이스 B가 객체의 메소드를 호출할 수 있으려면 객체는 A.B 2개의 인터페이스를 모두 구현 해야합니다. 따라서 구현 클래스는 위에 처럼 작성 되어야 합니다.

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

만약 하나라도 없으면 추상 클래스로 선언을 홰야합니다.

 

인터넷 검색을 할수있는 Searcjalbe 인터페이스를 만들어 보았습니다.

package book;

public interface Searchable {
	
	void search(String url);
}

search() 추상 메소드는 매게값으로 URl을 받습니다.

만약 SmartTelevision 이 인터넷 검색 기능도 제공한다면 RemoteControl과 Searchable을 모두 구현한 SmartTelevision 클래스를 다음과 같이 작성할 수 있습니다.

 

package book;

// 구현부 implements
public class SmartTelevision implements RemoteControl, Searchable {
									
	// 필드 선언
	private int volume;
	
	// RemoteControl 에는 추상메소드가 3개가 있기때문에
	// 이 메서드들의 대한 실체 메서드를 가지고있어야함
	@Override
	public void turnOn() {
		System.out.println("Tv를 켭니다.");
		
	}

	@Override
	public void turnOff() {
		System.out.println("Tv를 끕니다.");
		
	}

	@Override
	// 인터페이스 상수를 이용해서 volume필드의 값을 제한함
	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 볼륨 : "+volume);
	} 
	// 여기까지가 RemoteControl 의 추상메서드에 관한 실체 메서드

	@Override
	// Searchable의 추상메서드에 관한 실체 메서드
	public void search(String url) {
		// TODO Auto-generated method stub
		System.out.println("url +"+"을 검색합니다.");
		
	}

}

개발 코드에서 인터페이스는 클래스의 필드, 생성자 or 메서드의 매개 변수. 생성자or 메서드의 로컬 변수로 선언될 수 있습니다.

package book;

public class MyClass {

	// 필드 RemoteControl rc
	RemoteControl rc = new Television();
	
	// 생성자 
	// RemoteControl rc <- MyClass mc = new MyClass(new Television());
	MyClass(RemoteControl rc) {
		this.rc = rc;
	}
	
	// 메소드
	void methodA() {
		// 로컬 변수
		RemoteControl rc = new Audio();
	}
	
	// RemoteControl rc = mc.methodB(new Audio());
	void methodB(RemoteControl rc) {}
}

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

개발 코드에서 RemoteControl의 변수 rc로 turnOn() or turnOff() 메서드를 호출하면 구현 객체의 turnOn()과 turnOff() 메서드가 자동 실행됩니다.

RemoteControl rc = new Television();

rc.turnOn(); -> Television의 turnOn() 실행
rc.turnOff(); -> Television의 turnOff() 실행

인터페이스를 사용 해보겠습니다.

package book;

public class RemoteControlEx {

	public static void main(String[] args) {
		/*
		 * RemoteControl rc; 
		 * rc = new Television(); 
		 * rc = new Audio();
		 */
		RemoteControl rc = null; // <-인터페이스 변수 선언
		
		rc = new Television(); // <- Television 객체를 인터페이스 타입에 대입
		
		rc.turnOff();
		rc.turnOn(); // <-인터페이스의 turnOn(),turnOff() 호출
		
		rc = new Audio(); // <- Audio 객체를 인터페이스 타입에 대입함
		
		rc.turnOn();
		rc.turnOff(); //<-인터페이스의 turnOn(),turnOff() 호출

	}
}

코드를 작성하고 작동시키면

'JAVA' 카테고리의 다른 글

인터페이스 (default method)  (0) 2022.05.25
2022년 5월 25일 수업중 과제 : 계산기 프로그램  (0) 2022.05.25
상수의 데이터 타입  (0) 2022.05.15
변수  (0) 2022.05.15
데이터 타입  (0) 2022.05.15