8. 인터페이스
8.1 인터페이스 역할
인터페이스 웹 개발할때 많이 사용됨.
다형성 부여에 필요한 기술임 인터페이스는. 즉 인터페이스 = 다형성이다.
사전적의미로 두 장치를 연결하는 접속기
인터페이스는 두 객체를 연결하는 역할을 한다.
직접 호출하면 간단할텐데 인터페이스를 쓰는이유?
객체B에는 매우 많은 필드 메소드가 있기때문에 호출한는 객체A가 다 알 필요가 없다.
자동차 운전할때 자동차 부품을 다 알지 않아도 되듯이 계기판이 인터페이스 역할을 하는 것임.
객체 A가 인터페이스의 메소드를 호출하면 실제 로 진행되는 것은 인터페이스 뒤편의 객체B 이다.
장점은 인터페이스 뒤의객체 B가 C로 교체되어도 문제가 생기지 않는다.
실행결과가 다르게 설계되었으면 객체A는 객체 교체로 인해 다른 결과를 얻게되는 것이다.
따라서 다형성을 구현하는데 주된 기술로 이용되고 상속보다 인터페이스를 이용해서 다형성을 구현하는 경우가 더많다.
8.2 인터페이스와 구현 클래스 선언
인터페이스는 .java소스파일로 작성되고 ~.class 형태로 컴파일되기 땜누에 물리적형태는 클래스와 동일
그러나 소스를 작성할때 선언하는 방법과 구성 멤버가 클래스와 다르다.
8.2.1 인터페이스 선언
인터페이스 선언은 class대신 interface키워드를 사요한다.
[public] interface 인터페이스명{}
public 상수필드 public 추상메소드 public 디폴트메소드 public 정적메소드 private 메소드 private 정적메소드
리모컨을 이용해서 상호작용을 한다고 생각해서 RemoteControl을 인터페이스로 만드는거임.
package ch08.sec02;
public interface RemoteControl {
//추상메소드선언
public void turnOn();인터페이스로 turnOn을 사용할수잇다.라고 이해가능 인터페이스를 통해서 실제 사용되는 객체의 turnOn이 실행됨
인터페이스는public을 안붙여도 기본이 public임. abstract 생략해도 추상메소드임.
RemoteControl인터페이스로 trunOn을 사용할수잇다.라고 생각
리모콘을 누르지만 실제 켜지는건 티비라고 생각하면됨.
8.2.2 구현클래스 선언
객체A가 인터페이스의 추상 메소드를 호출하면 객체B의 메소드를 실행한다.
객체B는 인터페이스에 선언된 추상메소드와 도일한 선언부를 가진(재정의된)메소들르 가지고있어야함.
원래있는데 다시선언하는게 재정의임 (상속관련x여도)
객체 B에 인터페이스를 구현한(implement)한 객체라고 한다.
public class B implements 인터페이스명{}
package ch08.sec02; //클래스이름에 빨간줄그어져서 구현하라고 나오는데 거기 눌러서도 가능.
public class Televison implements RemoteControl{
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
//인터페이스 이미 public이라 최소 public 붙여야함. 강화불가능!
}
}8.2.3 변수 선언과 구현객체 대입
인터페이스도 하나의 타입의므로 변수의 탕비으로 사용할 수 있다.
인터페이스는 참조타입에 속하므로 인터페이스 변수에는 객체를 참조하고 있지않다는 뜻으로 null을 대입할수있다.
RemoteControl rc;
RemoteControl rc = null;
rc = new Television(); rc.trunOn();
//rc변수에 Televison 객체를 대입
RemoteControl rc = new Televison();
rc.turnOn();
//rc변수에는 RemoteControl을 구현한 어떠한 ㄱ개체든 대입이 가능하다.
// 만약 Audio객체가 구현객체라면 당므과 같이 Audio객체로 교체해서 대입가능하다.
//rc변수에 Audio 객체를 대입(교체시킴)
rc = new Audio();
rc.turnOn(); 
8.3 상수필드
인터페이스는 상수필드를 멤버로 가질 수 있다.
인터페이스에 선언된 필드는 모두 public static final 특성을 갖기 때문에 생략하더라도 자동적으로 컴파일과정에서 붙는다.
상수명은 대문자로 작성하되 서로 다른 단어로 구성되어있을경우 언더바로 연결하는게 관례이다.
package ch08.sec03;
public interface RemoteControl {
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
}package ch08.sec03;
public class RemoteControlExample {
public static void main(String[] args) {
System.out.println("리모콘 최대 볼륨: " + RemoteControl.MAX_VOLUME); //10
System.out.println("리모콘 최소 볼륨: " + RemoteControl.MIN_VOLUME); //0
}
}8.4 추상메소드
인터페이스는 구현 클래스가 재정의해야햐는 public 추상메소드를 멤버로 가질수 있다.
package ch08.sec04;
public interface RemoteControl {
//상수필드
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
//추상메소드
void turnOn();
void turnOff();
void setVolume(int volume);
}//필드
private int volume;
//추상메소드 오버라이딩
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
//추상메소드 오버라이딩
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
}
//추상메소드 오버라이딩
@Override
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);
}
}//필드
private int volume;
//추상메소드 오버라이딩
@Override
public void turnOn() {
System.out.println("Audio를 켭니다.");
}
//추상메소드 오버라이딩
@Override
public void turnOff() {
System.out.println("Audio를 끕니다.");
}
//추상메소드 오버라이딩
@Override
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);
}
} //인터페이스 변수선언
RemoteControl rc;
//텔레비젼 객체 생성후 인터페이스 변수에 대입
rc = new Televison();
rc.turnOn();
rc.setVolume(5);
rc.turnOff();
rc = new Audio();
rc.turnOn();
rc.setVolume(5);
rc.turnOff();
8.5 디폴트 메소드
인터페이스에는 완전한 실행코드를 가진 디폴트 메소드를 선언할수잇다. 추상 메소드는 실행부 {}가 없지만 디폴트 메소드는 실행부가 있다.
선언방법은 클래스 메소드와 동일한데 차이점은 default키워드가 리턴타입앞에 붙는다.
[public] default 리턴타입 메소드명(매개변수,...){}
디폴트 메소드의 실행부에는 상수필드를 읽ㄱ거나 추상메소드를 호출하는 코드를 작성할수있다.
RemoteControl 안에 무음 처리 기능을 제공하는 setMute()디폴트 메소드를 선언해보자.
package ch08.sec05;
public interface RemoteControl {
//상수필드
int MAX_VOLUME = 10;
int MIN_VOLUME = 0;
//추상메소드
void turnOn();
void turnOff();
void setVolume(int volume);
//디폴트 인스턴스 메소드
default void setMute(boolean mute)
{
if(mute)
{
System.out.println("무음 처리합니다.");
//추상메소드 호출하면서 상수필드 사용
setVolume(MIN_VOLUME);
}
else
{
System.out.println("무음 해제합니다.");
} 구현클래스는 디폴트 메소드를 재정의해서 자신에 맞게 수정할 수도있다. 재정의시 public접근제한자를 반드시 붙이고 default키워드를 생략해야한다.
//전 장의 오디오 클래스 추가 필드 선언
private int memoryVolume;
@Override
public void setMute(boolean mute) {
if(mute)
{
this.memoryVolume = this.volume;
System.out.println("무음처리 합니다.");
setVolume(RemoteControl.MIN_VOLUME);
}
else
{
System.out.println("무음해제 합니다.");
setVolume(this.memoryVolume);
//mute가 false일경우 원래 볼륨으로 복원하는 코드
}
}//디폴트 메소드는 구현객체가 필요한 메소드이다. 따라서 호출하려면 Television객체를 다음과 같이 인터페이스 변수에 대입하고 나서 setMute()를 호출해야한다.
//인터페이스 변수선언
RemoteControl rc;
//텔레비젼 객체 생성후 인터페이스 변수에 대입
rc = new Televison();
rc.turnOn();
rc.setVolume(5);
//디폴트 메소드 호출
rc.setMute(true);
rc.setMute(false);
//오디오 클래스에 추가 후
System.out.println();
rc = new Audio();
rc.turnOn();
rc.setVolume(5);
//디폴트 메소드 호출
rc.setMute(true);
rc.setMute(false);
8.6 정적메소드
인터페이스에는 정적 메소드 선언도 가능하다.
추상메소드와 디폴트 메소드는 구현객체가 필요하디만 정적메소드는 구현객체가 없어도 인터페이스만으로 호출가능
선언방법은 클래스 메소드와 완전 동일
[public | private] static 리턴타입 메소드명(매개변수, ...){}
//정적메소드
static void changeBattery()
{
System.out.println("리모콘 건전지를 교환합니다.");
}//정적메소드 호출
RemoteControl.changeBattery(); //리모콘 건전지를 교환합니다.주의할점은 실행부를 작성할때 추상메소드 디폴트 메소드 private메소드를 호출할 수없다.
위의 메소드는 구현객체가 필요한 인스턴스 메소드 이기때문
8.7 private 메소드
인터페이스의 상수필드 추상메소드 디폴트 메소드 정적메소드는 모두 public접근 제한을 갖는다.
이 멤버들을 선언할때는 생성하더라도 컴파일과정에서 자동으로 붙는다.
또한 외부에서 접근할 수 없는 private 메소드선언도 가능하다.
private메소드는 디폴트 멤소드 안에서만 호출이 가능한 반면
private 정적 메소드는디폴트메소드 뿐만 아니라 정적 메소드 안에서도 호출이 가능하다.
private 메소드의 용도는 디폴트와 정적 메소드들의 중복코드를 줄이기 위함이다.
다음은 service인터페이스에서 2개의 디폴트메소드와 2개의 정적메소드 중
중복코드 부분을 각각 private메소드와 private정적메소드로 선언하고 호출하는 방법이다.
package ch08.sec07;
public interface Service {
//디폴트 메소드
default void defaultMethod1()
{
System.out.println("defaultMethod1 종속 코드");
defaultCommon();
}
default void defaultMethod2()
{
System.out.println("defaultMethod2 종속 코드");
defaultCommon();
}
//private 메소드
private void defaultCommon()
{
System.out.println("defaultMethod1 중복 코드");
System.out.println("defaultMethod2 중복 코드");
}
//정적 메소드
static void staticMethod1()
{
System.out.println("staticMethod1 종속 코드");
staticCommon();
}
static void staticMethod2()
{
System.out.println("staticMethod2 종속 코드");
staticCommon();
}
private static void staticCommon()
{
System.out.println("staticMethod1 중복 코드");
System.out.println("staticMethod2 중복 코드");
}//인터페이스 변수 선언과 구현 객체 대입
Service service = new ServiceImpl();
//디폴트 메소드 호출
service.defaultMethod1();
System.out.println();
service.defaultMethod2();
System.out.println();
//정적메소드 호출
Service.staticMethod1();
System.out.println();
Service.staticMethod2();
System.out.println(); 
8.8 다중인터페이스 구현
구현 객체는 여러개의 인터페이스를 implements할수있다. 구현객체가 인터페이스A와 인터페이스B를 구현하고있다면
각각의 인터페이스를 통해 구현객체를 사욯알수잇다.
왜? 인터페이스는 사용설명서 이기때문에 사용방법을 다르게해서 객체를 이용하고 싶을때 이렇게 사용한다.
public class 구현 클래스명 implements 인터페이스A, 인터페이스B {//모든 추상메소드 재정의}
인터페이스A변수 = new 구현클래스명 인터페이스B변수 = new 구현클래스명
package ch08.sec08;
public interface RemoteControl {
void turnOn();
void turnOff();
}package ch08.sec08;
public interface Searchable {
//추상메소드
void search(String url);
} package ch08.sec08;
public class SmartTelevison implements RemoteControl, Searchable{
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
}
@Override
public void search(String url) {
System.out.println(url + "을 검색합니다.");
}
}RemoteControl rc = new SmartTelevison();
rc.turnOn();
rc.turnOff();
Searchable serchable = new SmartTelevison();
serchable.search("www.youtube.com");
8.9 인터페이스 상속
인터페이스도 다른 인ㄴ터페이스를 상속할수잇으며 클래스와는 달리 다중상속을 허용한다.
자식인터페이스의 구현클래스는 자식인터페이스의 메소드 뿐만 아니라 부모 인터페이스의 모든 추상 메소드를 재정의해야한다.
구현객체는 자식 및 부모 인터페이스 변수에 대입가능하다.
package ch08.sec09;
public interface InterfaceA {
//추상메소드
void methodA();
} package ch08.sec09;
public interface InterfaceB {
//추상메소드
void methodB();
}package ch08.sec09;
public interface InterfaceC extends InterfaceA, InterfaceB{
//추상메소드
void methodC();
}package ch08.sec09;
public class InterfaceClmpl implements InterfaceC {
@Override
public void methodA() {
System.out.println("InterfaceClmpl-methodA() 실행");
}
@Override
public void methodB() {
System.out.println("InterfaceClmpl-methodB() 실행");
}
@Override
public void methodC() {
System.out.println("InterfaceClmpl-methodC() 실행");
}
}InterfaceClmpl impl = new InterfaceClmpl();
InterfaceA ia = impl;
ia.methodA();
System.out.println();
InterfaceB ib = impl;
ib.methodB();
System.out.println();
InterfaceC ic = impl;
ic.methodA();
ic.methodB();
ic.methodC();
'기초단계 > JAVA' 카테고리의 다른 글
| 2022.11.23-1 JAVA 중첩 선언과 익명개체 (0) | 2022.11.23 |
|---|---|
| 2022.11.20-2 JAVA 인터페이스 2 (0) | 2022.11.20 |
| 2022.11.19-2 JAVA 상속 2 (0) | 2022.11.20 |
| 2022.11.19-1 JAVA 상속 1 (0) | 2022.11.20 |
| 2022.11.18-1 JAVA 클래스 4 (0) | 2022.11.18 |