1. 인터페이스란?
2. 인터페이스 구조
3. 인터페이스 구현
1. 인터페이스란?
인터페이스는 interface라고 합니다. 이 영어 단어를 inter + face로 단어를 나눠보면, inter는 '~사이에' 라는 의미를 가지고 는데요, 인터스텔라라는 영화도 스텔라는 별, 행성이라는 뜻이므로 행성과 행성 '사이'라는 뜻으로 해석할 수 있습니다. 그리고 face는 얼굴이라는 뜻도 있지만, 면/표면이라는 뜻도 있습니다. 그래서 interface라는 단어를 직역해보면 표면과 표면 사이라는 의미가 됩니다.
프로그램과 프로그램 사이의 표면을 연결해주는 인터페이스라는 것을 두게 되면 프로그램A는 이 인터페이스를 실행하고 인터페이스에서는 프로그램B를 실행하게 됩다. 실행이 끝나면 프로그램B는 인터페이스로 실행결과를 리턴하고, 인터페이스는 프로그램A로 다시 리턴하게 됩다. 이것이 인터페이스의 역할입니다.
대표적인 인터페이스가 활용되는 예가 있는데요, 여러분들 웹사이트를 돌아다니다 보면 네이버지도나 구글지도가 들어가 있는 페이지를 많이 봤을 것입니다. 이 웹페이지에서는 직접 네이버나 구글 지도 프로그램을 실행하지 않습니다. 정확히 얘기하면 실행할 수 없습니다. 이 웹페이지에서는 지도 API를 사용해서 필요한 기능을 사용하게 되는데요, 이 API가 바로 Application Programming Interface의 약자입니다. 요즘은 데이터분석을 위한 통계데이터를 제공하는 공공기관이나 민간기관도 점점 늘고 있는데, 이때 파일을 직접 제공해주는 기관도 있지만, API를 통해 데이터를 제공해주는 경우도 많이 있습니다.
또, 여러분이 컴퓨터와 상호작용하기 위해 모니터에 출력되는 화면을 UI라고 합니다. 이 UI를 통해 사용자는 버튼을 클릭하고, 컴퓨터는 결과를 화면에 출력하게 되죠. 이 UI가 User Interface의 줄임말입니다.
상호작용이라는 말도 많이 들어보셨죠? 인터렉션이라고도 부릅니다. interaction 도 inter와 action이 결합된 단어입니다. 느낌이 오시죠?
이렇게 직접 프로그램이나 시스템에 접근해서 실행하는 것이 아니라 중간에 인터페이스를 이용해서 처리하게 됩니다.
이제 자바에 적용해서 확인해보겠습니다.
프로그램 실행 중 객체A를 실행하고자 할때 직접 실행(호출)하는 것이 아니라 인터페이스를 통해 실행(호출)하게 됩니다. 그러면 이제 도대체 왜 실행 코드에서 객체A를 직접 실행하지 않고, 힘들게 인터페이스를 하나 더 만들어서 불편하게 만들었을까요?
다시 객체지향 프로그래밍 관점으로 생각해보겠습니다. 객체A, 객체B, 객체C는 별개의 부품으로 생각해 보세요. 프로그램이 수정되거나, 새로운 기능이 추가되어도, 실행코드를 직접 수정하지 않고, 부품만 추가하거나 교체하면 되는 것입니다.
2. 인터페이스 구조
인터페이스를 정의할 때는 class 키워드 대신 interface 라는 키워드를 사용해서 정의합니다. 인터페이스는 상수와 메서드들로 구성되는데, 인터페이스 파일을 생성할 때 이클립스 메뉴에서 File > New > Interface로 선택하면 됩니다. 인터페이스의 메서드는 이전 자바 7버전까지는 추상 메서드만 선언이 가능했는데, 자바 8번전 이후부터는 default 메서드와 static 메서드도 선언이 가능합니다. 그리고 인터페이스는 객체로 생성되어 질 수 없습니다.
[public] interface 인터페이스명 {
[public static final] 자료형 상수명 = 값; // 상수
[public abstract] 리턴타입 추상메서드명(); // 추상메서드
[public] default 리턴타입 메서드명(매개변수...) {...} // default 메서드
[public] static 리턴타입 메서드명(매개변수...) {...} // static 메서드
}
상수
인터페이스 내의 필드는 상수만 선언할 수 있습니다. 상수는 public static final 키워드가 적용되는데 생략하면 컴파일 시에 자동으로 포함해 줍니다. 그리고 선언 시 반드시 초기값을 대입해줘야 합니다.
package example;
public interface InterfaceEx {
// 상수
public int MIN_PRICE = 0;
public int MAX_PRICE = 100000;
}
추상 메서드
인터페이스의 메서드는 기본적으로 추상 메서드로 선언되는데, 모든 추상 메서드는 public abstract 키워드가 붙습니다. 역시 생략해도 컴파일 과정에서 자동으로 넣어 주게 됩니다.
package example;
public interface InterfaceEx {
// 상수
public int MIN_PRICE = 0;
public int MAX_PRICE = 100000;
// 추상 메서드
public double meanPrice();
public double totalPrice();
}
default 메서드
default 메서드는 자바 8버전에서 추가되었으며, 구현부(실행 블록)가 있는 메서드입니다. default 키워드를 반드시 붙여야 하며, 접근제한자는 생략하는 경우 public으로 컴파일 과정에서 추가됩니다.
package example;
public interface InterfaceEx {
// 상수
public int MIN_PRICE = 0;
public int MAX_PRICE = 100000;
// 추상 메서드
public double meanPrice();
public double totalPrice();
// default 메서드
default double getSalePrice(double price) {
return price - (price * 0.05);
}
}
static 메서드
static 메서드도 자바 8버전에서 추가되었으며, default 메서드와 마찬가지로 구현부를 가지고 있는 메서드입니다. static 메서드는 객체 없이 인터페이스만으로 호출이 가능한 메서드입니다.
package example;
public interface InterfaceEx {
// 상수
public int MIN_PRICE = 0;
public int MAX_PRICE = 100000;
// 추상 메서드
public double meanPrice();
public double totalPrice();
// default 메서드
default double getSalePrice(double price) {
return price - (price * 0.05);
}
// static 메서드
static void printPrice(double price) {
System.out.println(price);
}
}
인터페이스의 특징
1. 클래스 간 -> 상속, 인터페이스와 클래스 간 -> 구현
2. 객체생성 불가, 구현 클래스로 객체 생성
3. 다중 구현 가능
4. 인터페이스간의 상속 가능 (인터페이스 간은 다중 상속도 가능)
5. 인터페이스의 모든 멤버의 접근 제한자는 public
6. 인터페이스의 모든 멤버 변수는 final이 붙은 상수
3. 인터페이스 구현
인터페이스의 추상 메서드들을 일반 메서드에서 구현부를 정의할 수 있는데, 이를 구현(implements)한다라고 표현합니다. 구현하는 클래스를 구현 클래스라고 하고, 인터페이스와 구현 클래스와의 관계도 상속관계에서처럼 상위, 하위 관계가 성립됩니다. 또한 인터페이스에서 정의한 모든 추상 메서드들은 반드시 구현 클래스에서 구현해줘야 합니다.
구현 클래스에서는 implements 키워드를 사용하고 뒤에 인터페이스 이름을 명시합니다.
public class 구현클래스명 implements 인터페이스명 {
// 인터페이스의 모든 추상메서드 반드시 구현
...
}
이제 구현 클래스를 구현해보도록 하겠습니다. Printer와 Scanner, Fax라는 인터페이스를 만들고, 이 세 개의 인터페이스를 한번에 구현하는 Complexer라는 구현 클래스를 만들 것입니다. 이 구현 클래스는 Printer와 Scanner, Fax 인터페이스의 모든 추상 메서드를 전부 구현해야 합니다.
Printer.java
package example;
public interface Printer {
int INK = 100;
void print();
}
Scanner.java
package example;
public interface Scanner {
void scan();
}
Fax.java
package example;
public interface Fax {
String FAX_NUMBER = "02-1234-5678";
void send(String tel);
void receive(String tel);
}
Complexer.java
package example;
public class Complexer implements Printer, Scanner, Fax {
@Override
public void send(String tel) {
System.out.println(FAX_NUMBER + "에서 "+tel+"로 FAX 전송");
}
@Override
public void receive(String tel) {
System.out.println(tel + "에서 "+FAX_NUMBER+"로 FAX 수신");
}
@Override
public void scan() {
System.out.println("스캔 실행");
}
@Override
public void print() {
System.out.println("출력 실행");
}
}
ComplexerMain.java
package example;
public class ComplexerMain {
public static void main(String[] args) {
Complexer com = new Complexer();
System.out.println(Complexer.INK);
System.out.println(Complexer.FAX_NUMBER);
com.print();
com.scan();
com.send("02-8765-4321");
com.receive("02-8765-4321");
}
}
실행 결과
100
02-1234-5678
출력 실행
스캔 실행
02-1234-5678에서 02-8765-4321로 FAX 전송
02-8765-4321에서 02-1234-5678로 FAX 수신
Printer, Scaner, Fax 세 인터페이스를 먼저 생성한 후 Complexer라는 구현 클래스가 세 개의 인터페이스를 모두 구현하고 있습니다. Complexer.java 파일에서 implements 키워드 뒤에 세 개의 인터페이스를 모두 적어줬는데, 클래스 간의 상속은 하나의 클래스만 상속 가능했는데, 인터페이스의 구현은 여러 개의 인터페이스를 동시에 구현할 수 있습니다. 다중 구현이 가능합니다. 이 구현 클래스는 구현하고 있는 모든 인터페이스의 추상 메서드들을 모두 구현해야 하는데, 하나라도 빠지면 컴파일 에러가 발생하니 반드시 구현해줘야 합니다.
각 메서드 상단에 @Override라고 되어 있는데, @는 어노테이션이라고 부르는 컴파일러에게 알려주는 일종의 표시라고 생각하시면 됩니다. 그래서 이 @Override는 상위 클래스의 메서드를 오버라이딩하고 있다고 표시해주는 것입니다. 생략해도 실행하는데는 전혀 상관없지만, 오버라이딩이 제대로 안되거나 실수를 줄여주기 위해 붙여주는 것이 좋습니다.
이제 구현 클래스가 완성 되었으니 ComplexerMain 클래스에서는 구현 클래스를 객체화할 수 있게 됩니다. ComplexerMain.java 에서는 객체를 생성하고 상수를 객체 없이 클래스명으로 직접 호출하여 출력하고, 재정의된 메서드를 실행하고 있습니다. 실행 결과 역시 재정의된 메서드대로 정상적으로 출력된 것을 알 수 있습니다.