본문 바로가기
JAVA/객체지향

자바 인터페이스 의미, 특징, 선언, 구현 방법 (interface)

by 스코리아 2023. 9. 21.

안녕하세요, 스코리아입니다.

오늘은 자바 인터페이스의 의미와 특징, 선언, 구현 방법에 대해서 알아보겠습니다.

 

인터페이스 의미와 역할

  • 개발 코드와 객체가 서로 통신하는 접점
  • 개발 코드는 객체의 내부 구조를 알 필요가 없고 인터페이스의 메소드만 알고 있으면 됨

자바 인터페이스 구조

  • 개발코드가 객체를 종속되지 않게 하여 객체를 교체할 수 있음
  • 개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해짐 (다형성)

 

인터페이스 특징

  • 인터페이스의 모든 메소드는 추상 메소드로 선언됨 (public abstract)
  • 인터페이스의 모든 변수는 상수로 선언됨 (public static final)

 

인터페이스 선언

우선 인터페이스를 선언하는 방법은 다음과 같습니다.

public interface 인터페이스명{
	// 인터페이스
}

인터페이스에는 상수 필드, 디폴트 메소드, 추상 메소드, 정적 메소드를 선언할 수 있습니다.

하나씩 살펴보겠습니다.

 

(1) 상수 필드 선언

  • 인터페이스에는 필드 중에 '상수 필드'만 선언 가능 (데이터를 저장하지 않기 때문에 데이터를 저장할 인스턴스 또는 정적 필드가 필요 없음)
  • 즉, 인터페이스에 선언된 필드는 모두 public static final 특징을 가짐
  • 상수명은 대문자로 작성 (예시: int MAX_VALUE = 10;)
  • 선언과 동시에 초기값을 지정해주어야 한다.
  • [public static final] 타입상수명 = 값; (public static final 생략해도 됨)

(2) 추상 메소드 선언

  • 인터페이스를 통해 호출된 메소드는 최종적으로 객체에서 실행
  • 인터페이스의 메소드는 기본적으로 실행 블록이 없는 추상 메소드(abstract method)로 선언
  • 개발 코드 -> 인터페이스 (추상메소드: 메소드 선언과 호출 방법만 기술) -> 객체 (재정의된 메소드 : 실제 실행 메소드)
  • [public abstract] 리턴타입 메소드명(매개변수, ...); (public abstract 생략해도 됨)

(3) 디폴트 메소드 선언

  • 자바 8에서 추가된 인터페이스의 새로운 멤버
  • 실행 블록을 가지고 있는 메소드
  • [public] default 리턴타입 메소드명(매개변수, ...){ ... } (public 생략해도 됨)

(4) 정적 메소드 선언

  • 자바 8에서 추가된 인터페이스의 새로운 멤버
  • [public] static 리턴타입 메소드명(매개변수, ...) {... } (public 생략해도 됨)

 

구현 객체와 구현 클래스

  • 인터페이스의 추상 메소드에 대한 실체 메소드를 가진 객체를 '구현 객체'라고 한다.
  • 구현 객체를 생성하는 클래스를 '구현 클래스'라고 한다.
  • 개발 코드 -> 인터페이스 -> 객체 (구현 객체)

 

인터페이스 구현과 실체 메소드 작성

  • 인터페이스 구현을 위해 자신의 객체가 인터페이스 타입으로 사용할 수 있음을 'implements' 키워드로 명시
public class 구현클래스명 implements 인터페이스명 {
	// 인터페이스에 선언된 추상 메소드의 실체 메소드 구현
}
  • 메소드의 선언부가 정확히 일치해야 함
  • 인터페이스의 '모든' 추상 메소드를 재정의하는 실체 메소드를 작성해야 함 (일부만 재정의할 경우, 추상 abstract 클래스로 선언)
  • 인터페이스의 모든 메소드는 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근제한으로 작성할 수 없음
  • 인텔리제이 메소드 오버라이딩 단축키: CMD + O
  • @Override 어노테이션을 이용해서 정확하게 재정의 되었는지 컴파일러가 체크토록 한다.
RemoteControl rc = new Television();
// 인터페이스클래스이름 변수이름 = 구현 객체

 

예시와 함께 살펴보기

RemoteControl 인터페이스를 생성하기 위해 RemoteControl.java 파일을 만들고 다음과 같이 작성합니다.

public interface RemoteControl {
    /** 상수 필드
    	- 상수는 무조건 대문자로 작성, 값을 무조건 지정해야함
    	- public static final이 자동으로 붙음
    */
    int MAX_VOLUME = 10;
    int MIN_VOLUME = 0;

    /** 추상 메소드
    	- public abstract이 자동으로 붙음
    	- 선언만 하면 됨. 구현X
    */
    void turnOn();
    void turnOff();
    void setVolume(int volume);

    /** 디폴트 메소드
    	- public이 자동으로 붙음, default는 붙여야함
    	- 실행블록을 가지고 있음
    */
    default void setMute(boolean mute) {
        if (mute) {
            System.out.println("무음 처리합니다.");
        }else{
            System.out.println("무읍 해제합니다.");
        }
    }

    /** 정적 메소드
    	- public이 자동으로 붙음
    */
    static void changeBattery() {
        System.out.println("건전지를 교환합니다.");
    }
}

RemoteControl 인터페이스를 구현하는 Audio 클래스를 생성하기 위해 Audio.java 파일을 만들고 다음과 같이 작성합니다.

public class Audio implements RemoteControl {
    private int volume;
    private boolean mute;

    @Override
    public void turnOn() {
        System.out.println("오디오를 켭니다.");
    }

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

    @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("현재 오디오 볼륨 : " + this.volume);
    }

    // 디폴트 메소드 재정의
    @Override
    public void setMute(boolean mute) {
        this.mute = mute;
        if (mute) {
            System.out.println("오디오 무음 처리합니다.");
        }else{
            System.out.println("오디오 무음 해제합니다.");
        }
    }
}

RemoteControl 인터페이스를 구현하는 Television 클래스를 생성하기 위해 Television.java 파일을 만들고 다음과 같이 작성합니다.

public class Television implements RemoteControl {
    private int volume;

    @Override
    public void turnOn() {
        System.out.println("티비를 켭니다.");
    }

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

    @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("현재 티비 볼륨 : " + this.volume);
    }
}

RemoteControl 인터페이스의 구현 클래스인 Audio와 Television를 사용해 보기 위해 RemoteControlExample.java 파일을 만들고 다음과 같이 작성합니다.

public class RemoteControlExample {
    public static void main(String[] args) {
        // 인터페이스 사용
        RemoteControl rc = null;
        rc = new Television(); // 구현 객체를 인터페이스에 대입
        rc.turnOn(); // 구현 객체의 추상 메소드
        rc.turnOff();

        rc = new Audio(); // 구현 객체를 인터페이스에 대입
        rc.turnOn(); // 구현 객체의 추상 메소드
        rc.turnOff();

        // 구현 객체의 디폴트 메소드 (구현 클래스에서 오버라이딩 가능)
        rc.setMute(true); // 구현 객체가 인터페이스에 대입된 후 사용 가능
        
        // RemoteControl.setMute(true); -> 불가능

        // 구현 객체의 정적 메소드 (인터페이스로 직접 호출 가능)
        RemoteControl.changeBattery();
    }
}
  • RemoteControl 인터페이스구현 객체인 Television과 Audio를 각각 대입한 후, 추상메소드인 turnOn과 turnOff를 호출해 보았습니다.
  • 구현 객체의 디폴트 메소드를 사용했을때 특징은 다음과 같습니다.
    • 인터페이스만으로는 사용 불가 (RemoteControl.setMute(true);와 같이 호출 불가)
    • 즉, 구현 객체가 인터페이스에 대입되어야 호출될 수 있는 인스턴스 메소드 (RemoteControl rc = new Television();)
    • 모든 구현 객체가 가지고 있는 기본 메소드로 사용
      • 필요에 따라 구현 클래스가 디폴트 메소드를 재정의해서 사용 가능 (Audio 클래스처럼)
      • 디폴트 메소드를 추가하더라도 기존 구현 클래스들은 문제없이 사용 가능
    • 디폴트 메소드가 있는 인터페이스 상속 방법: 부모 인터페이스의 디폴트 메소드를 자식 인터페이스에서 활용하기
      • 디폴트 메소드를 단순히 상속
      • 디폴트 메소드를 재정의(Override)해서 실행 내용 변경
      • 디폴트 메소드를 추상 메소드로 선언 (구현 클래스에서 재정의해야 함)
  • 구현 객체의 정적 메소드를 사용했을 때 특징은 다음과 같습니다.
    • 인터페이스로 직접 호출 가능 (static 이므로)
    • RemoteControl.changeBattery(); 를 예시로 들 수 있음.

지금까지 자바(Java) 인터페이스의 의미와 특징, 선언, 구현 방법에 대해서 알아보았습니다.

읽어주셔서, 감사합니다.