나의 IT일지
인터페이스 본문
객체는 클래스에 구현되어 있는 특징을 바탕으로 생성이 된다. 이때, 객체들의 메서드는 같지만 다른 결과값을 출력해야 하는 경우가 있다. 이럴 경우에 추상 클래스를 사용하지만 인터페이스를 사용하기도 한다. 인터페이스란 객체의 기능을 정의한 타입으로, 다수의 객체에 대한 기본적인 기능을 정의한다.
인터페이스
인터페이스는 같은 이름의 메소드를 다른 결과값으로 출력하는 경우에 사용하는 타입으로, 추상클래스와 같은 기능을 한다. 그렇다면 추상클래스와 인터페이스를 구분하는 이유는 무엇일까?
추상클래스는 자식 객체의 특징을 확장하는 상속의 목적이라면, 인터페이스는 객체의 기능을 정의하는 구현의 목적이다. 그래서 같은 메서드로 요청할 때, 추상클래스는 객체에 직접 요청한다는 느낌이라면, 인터페이스는 객체에 간접적으로 요청한다는 느낌이다.
인터페이스 | 추상클래스 |
즉, 추상클래스는 설계는 비슷하지만 기능의 차이에 따라 객체가 바뀌는 미완성 설계도라면, 인터페이스는 객체들의 기본기능만 설계되어있는 기본 설계도이다.
인터페이스는 "interface"키워드로 선언이 되며, 블록은 추상메서드와 상수로 객체에 반드시 구현할 기능으로 구성되어 있어야 한다. 추가적으로, 인터페이스는 추상클래스처럼 객체를 생성할 수 없다.
interface 인터페이스명{ ... }; |
위의 구조는 인터페이스를 선언하는 방식으로, 클래스 선언과 똑같은 형식을 갖는다. 하지만 클래스의 경우에는 일반메서드와 일반 변수가 블록에 사용이 가능하지만 인터페이스의 경우에는 추상메서드(abstract)와 상수(final)만 해당 블록에서 사용된다.
인터페이스도 상속처럼 클래스에 선언한다. 다만 인터페이스라는 것을 구분하기 위해서 "extends"대신 "implements"를 사용한다. 이때, 인터페이스에 의해 구현된 클래스를 구현클래스라고 하며, 인터페이스에 구현된 모든 추상메서드는 반드시 전부 오버라이딩해야 한다.
class 클래스명 implements 인터페이스명{ ... } |
package pack0420;
interface Tourpack{
abstract void sightseeing();
void food();
}
class KoreaTour implements Tourpack{
public void sightseeing() {
System.out.println("경복궁 관람투어");
}
public void food() {
System.out.println("비빔밥 먹방투어");
}
}
class JapenTour implements Tourpack{
public void sightseeing() {
System.out.println("도쿄타워 관람투어");
}
public void food() {
System.out.println("초밥 먹방투어");
}
}
class TourGuide{
private Tourpack tour= new JapenTour();
public void sightseeing() {
tour.sightseeing();
}
public void food() {
tour.food();
}
}
package pack0420;
public class Code2 {
public static void main(String[] args) {
TourGuide guide = new TourGuide();
guide.food();
guide.sightseeing();
}
}
위의 코드를 보면 인터페이스의 추상 메소드는 구현 클래스에서 "public"접근제한을 가진다. 이는 인터페이스의 메서드는 기본적으로 "public"접근제한을 가지기 때문이다.
인터페이스는 추상클래스나 클래스 상속과 달리, 여러개의 인터페이스를 하나의 클래스에 구현할 수 있다.
interface Camera{
void photo();
}
interface Call{
void call();
}
interface Message{
void send();
}
class Phone implements Camera,Call,Message{
String name;
int space;
public void send() {
System.out.println("문자 보내기");
}
public void call() {
System.out.println("전화하기");
}
public void photo() {
System.out.println("사진찍기");
}
}
class PhoneUser{
public void send(Message phone) {
phone.send();
}
public void call(Call phone) {
phone.call();
}
public void photo(Camera phone) {
phone.photo();
}
}
package pack0420;
public class Code3 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Camera phone2 = new Phone();
Call phone3 = new Phone();
Message phone4 = new Phone();
PhoneUser user1 = new PhoneUser();
user1.call(phone1);
// user1.call(phone2); //사용불가
user1.call(phone3);
// user1.call(phone4); //사용불가
}
}
위의 코드를 보면 "Phone"클래스에 "Camera","Call","Message"인터페이스가 구현되는 것을 확인할 수 있다. 이때, "Phone"클래스는 구현되는 인터페이스의 추상메서드를 전부 오버라이딩 해야 한다.
추가적으로, 인터페이스를 통해 참조변수의 타입으로 선언할 수 있지만, 객체는 해당 인터페이스를 구현하고 있는 객체를 생성해야 한다. 그리고 인터페이스를 타입으로 가진 참조변수는 해당 인터페이스의 메서드나 상수만 호출할 수 있다.