본문 바로가기
언어/JAVA

[인터페이스]

by 코딩맛집 2023. 1. 30.

8.1 인터페이스 역할

인터페이스의 사전적 의미 : 두 장치를 연결하는 접속기

인터페이스 사용 이유 :  만약 인터페이스가 없이 객체 A가 객체 B를 직접 사용한다면 객체 A의 소스 코드를 객체 B에서 C로 변경하는 작업이 추가로 필요할 것이다. 

객체 A가 인터페이스의 메소드를 호출하면 실제로 실행되는 것은 인터페이스 뒤편의 객체 B 또는 객체 C의 메소드이다. 만약 객체 B의 메소드 실행 결과와 객체 C의 메소드 실행 결과가 다르다면, 객체 A는 객체 교체로 인해 다른 결과를 얻게 된다. 이 특징으로 인해 인터페이스는 다형성 구현에 주된 기술로 이용된다. 상속을 이용해서 다형성을 구현할 수도 있지만, 인터페이스를 이용해서 다형성을 구현하는 경우가 더 많다.

 

8.2 인터페이스와 구현 클래스 선언

인터페이스는 '~.java' 형태의 소스 파일로 작성되고 '~.class' 형태로 컴파일되기 때문에 물리적 형태는 클래스와 동일하다. 단, 소스를 작성할 때 선언하는 방법과 구성 멤버가 클래스와 다르다.

 

인터페이스 선언

접근 제한자로는 같은 패키지 내에서만 사용 가능한 default, 패키지와 상관없이 사용하는 public을 붙일 수 있다. 중괄호 안에는 인터페이스가 가지는 멤버들을 선언할 수 있다.

interface 인터페이스명 {}
public interface 인터페이스명 {
    //public 상수 필드
    //public 추상 메소드
    //public 디폴트 필드
    //public 정적 메소드ㅡ
    //private 메소드
    //private 정적 메소드
}

 

구현 클래스 선언

객체 A가 인터페이스의 추상 메소드를 호출하면 인터페이스는 객체 B의 메소드를 실행한다. 그렇다면 객체 B는 인터페이스에 선언된 추상 메소드와 동일한 선언부를 가진 메소드를 가지고 있어야 한다. 여기서 객체 B를 인터페이스를 구현한 객체라고 한다. 객체 B는 다음과 같이 인터페이스를 구현하고 있음을 선언부에 명시해야 한다.

public class B implements 인터페이스명 {}

implements 키워드는 해당 클래스가 인터페이스를 통해 사용할 수 있다는 표시이며, 인터페이스의 추상 메소드를 재정의한 메소드가 있다는 뜻이다.

 

변수 선언과 구현 객체 타입

인터페이스도 하나의 타입이므로 변수의 타입으로 사용할 수 있다. 인터페이스는 참조 타입에 속하므로 인터페이스 변수에는 객체를 참조하고 있지 않다는 뜻으로 null을 대입할 수 있다. 인터페이스를 통해 구현 객체를 사용하려면, 인터페이스 변수에 구현 객체의 번지를 대입해야 한다.

rc = new Television();

만약 Television이 implements RemoteControl로 선언되지 않았다면 RemoteControl 타입의 변수 rc에 대입할 수 없다. 인터페이스 변수에 구현 객체가 대입이 되었다면 변수를 통해 인터페이스의 추상 메소드를 호출할 수 있게 된다. rc 변수에는 RemoteControl을 구현한 어떠한 객체든 대입이 가능하다. 

public class RemoteControlExample {
    public static void main(String[] args){

        RemoteControl rc = new Television();
        rc.turnOn();
    }
}
//출력
//TV를 켭니다.

 

8.3 상수 필드

인터페이스에 선언된 필드는 모두 public static final 특성을 갖기 떄문에 생략하더라도 자동적으로 컴파일 과정에서 붙게 된다. 상수명은 대문자로 작성하되, 서로 다른 단어로 구성되어 있을 경우에는 언더바로 연결하는 것이 관례이다. 

#RemoteControl.java

public interface RemoteControl {
    int MAX_VOLUME = 10;
    int MIN_VOLUME = 0;
}

상수는 구현 객체와 관련 없는 인터페이스 소속 멤버이므로 다음과 같이 인터페이스로 바로 접근해서 상수값을 읽을 수 있다.

#RemoteControlExample

public class RemoteControlExample {
    public static void main(String[] args){
        System.out.println("리모콘 최대 볼륨: " + RemoteControl.MAX_VOLUME);
        System.out.println("리모콘 최소 볼륨: " + RemoteControl.MIN_VOLUME);
    }
}

 

8.4 추상 메소드

추상 메소드는 리턴 타입, 메소드명, 매개변수만 기술되고 중괄호 { }를 붙이지 않는 메소드를 말한다. public abstract를 생략하더라도 컴파일 과정에서 자동으로 붙게 된다. 추상 메소드는 객체 A가 인터페이스를 통해 어떻게 메소드를 호출할 수 있는지 방법을 알려주는 역할을 한다. 인터페이스 구현 객체 B는 추상 메소드의 실행부를 갖는 재정의된 메소드가 있어야 한다.

public interface RemoteControl {

    int MAX_VOLUME = 10;
    int MIN_VOLUME = 0;

    void turnOn();
    void turnOff();
    void setVolume(int volume);
}
public class Television implements RemoteControl{
    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);
    }
}

구현 클래스에서 추상 메소드를 재정의할 때 주의할 점은 인터페이스의 추상 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제한으로 재정의할 수 없다. 그래서 재정의되는 메소드에는 모두 public이 추가되어 있다.

 

8.5 디폴트 메소드

인터페이스에는 완전한 실행 코드를 가진 디폴트 메소드를 선언할 수 있다. 추상 메소드는 실행부가 없지만, 디폴트 메소드는 실행부가 있다. 선언 방법은 클래스 메소드와 동일한데, 차이점은 default 키워드가 리턴 타입 앞에 붙는다.

default void setMute(boolean mute) { }

디폴트 메소드의 실행부에는 상수 필드를 읽거나 추상 메소드를 호출하는 코드를 작성할 수 있다.  디폴트 메소드는 구현 객체가 필요한 메소드이다. 구현 클래스는 디폴트 메소드를 재정의해서 자신에게 맞게 수정할 수도 있다. 

 

※재정의 시 주의할 점

public 접근 제한자를 반드시 붙여야 하고, default 키워드를 생략해야 한다. 

 

8.6 정적 메소드

인터페이스에는 정적 메소드도 선언이 가능하다. 선언 방법은 클래스 정적 메소드와 완전 동일하다. 단, public을 생략하더라도 자동으로 컴파일 과정에서 붙는 것이 차이점이다.

 

추상 메소드와 디폴트 메소드와의 차이점!

구현 객체가 없어도 인터페이스만으로 호출할 수 있다.

[public | private] static 리턴타입 메소드명(매개변수, ) { }

※ 호출시 주의점

정적 메소드의 실행부를 작성할 때 주의할 점은 상수 필드를 제외한 추상 메소드, 디폴트 메소드, private 메소드 등을 호출할 수 없다는 것이다. 이 메소드는 구현 객체가 필요한 인스턴스 메소드이기 때문이다.

 

8.7 private 메소드

인터페이스의 상수 필드, 추상 메소드, 디폴트 메소드, 정적 메소드는 모두 public 접근 제한을 갖는다. 이 멤버들을 선언할 때는 public을 생략하더라도 컴파일 과정에서 public 접근 제한자가 붙어 항상 외부에서 접근이 가능하다. 또한 인터페이스에 외부에서 접근할 수 없는 private 메소드 선언도 가능하다.

구분 설명      
private 메소드 구현 객체가 필요한 메소드 default 메소드 안에서만 호출 가능
private 정적 메소드 구현 객체가 필요 없는 메소드 default 메소드, static 메소드 안에서도 호출 가능

private 메소드의 용도: 디폴트와 정적 메소드들의 중복 코드를 줄이기 위함이다.

'언어 > JAVA' 카테고리의 다른 글

[중첩 클래스]  (0) 2023.02.05
[chapter5] 확인 문제  (2) 2023.01.30
[상속]  (0) 2023.01.28
[클래스] 인스턴스 멤버, 정적 멤버, final, package, Getter Setter, 싱글톤 패턴  (0) 2023.01.27
[클래스]  (0) 2023.01.26