ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java]STEP1 - 13) 인터페이스(Interface)
    개발 공부/Java 2020. 9. 29. 16:20

     

    본 게시글은 도서 "이것이 자바다" 동영상 강의를 듣고 기록하는 TIL(Today I Learned) 입니다.
    모든 저작권은 출판사 한빛미디어와 신용권님께 있음을 알립니다.👍

     

     

    이번 게시글에서는 자바의 인터페이스에 대해 알아보도록 하겠습니다.

     

     

    1. 인터페이스의 역할과 선언


    인터페이스(Interface) : 객체의 사용 방법을 정의한 타입. 개발 코드와 객체가 서로 통신하는 접점 역할을 한다.

     

    쉽게말해서 인터페이스는 개발 코드와 객체 사이에서 중간 다리 역할을 하는 것이다.

    인터페이스를 사용하게 되면, 개발 코드를 수정하지 않고도 사용하는 개체를 변경할 수 있게 된다.

    즉 코드의 변경 없이 실행 내용과 리턴값을 다양화 할 수 있다는 장점을 가지게 된다.

     

     

    인터페이스 선언은 다음과 같이한다.

    [public, default] interface 인터페이스이름 {
     ....
    }
    • 인터페이스는 public 혹은 default만 올 수 있다. private이나 protected는 올 수 없다.
    • 인터페이스 이름은 영어 대소문자를 구분한다.
    • 첫 문자를 대문자로 하고 나머지는 소문자로 작성하는 것이 관례이다.

     

    인터페이스가 가질 수 있는 멤버는 다음과 같다.

     

    1) 상수 필드(Constant Field) 

    • 인터페이스는 데이터를 저장할 수 없기 때문에 인스턴스 필드나 정적 필드를 선언할 수 없다.
    • 대신 public static final을 이용해서 상수만 선언할 수 있다.
    • 인터페이스에 선언된 필드는 public static final을 생략하더라도 알아서 컴파일 할 때 붙는다.
    • public static final int PI = 3.141592; 와 같은 방식으로 선언한다.
    • 인터페이스는 정적 블록이 없으므로, 상수 선언 시 초기값을 반드시 지정해야한다.

     

    2) 추상 메소드(Abstract Method)

    • 인터페이스의 메소드는 실행 블록이 필요 없는 추상 메소드로 선언한다.
    • public abstract를 생략하더라도 자동적으로 컴파일 과정에서 붙는다.
    • 리턴 타입, 메소드명, 매개변수만 기술되고 중괄호는 붙이지 않는다.

     

    3) 디폴트 메소드(Default Method)

    • 자바 8부터 추가된 인터페이스의 새로운 멤버이다.
    • 형태는 클래스의 인스턴스 메소드와 동일하나, default 키워드가 앞에 붙게 된다.
    • public의 특성을 가지므로, public을 생략하더라도 자동적으로 컴파일 과정에서 붙는다.
    • 추상 메소드와 다른 점은 중괄호의 실행 블록이 있다는 것이다.
    • public default void setField(String field) {....} 와 같은 방식으로 선언한다.

     

    4) 정적 메소드(Static Method)

    • 디폴트 메소드와 마찬가지로 자바 8부터 추가된 인터페이스의 새로운 멤버이다.
    • public의 특성을 가지므로, public을 생략하더라도 자동적으로 컴파일 과정에서 붙는다.
    • 형태는 클래스의 정적 메소드와 완전 동일하다.
    • public static void setField(String field) {....}와 같은 방식으로 선언한다.

     

     

     


     

    2. 인터페이스의 구현


    개발 코드가 인터페이스 메소드를 호출하면 인터페이스는 객체의 메소드를 호출한다. 객체는 인터페이스에서 정의된 추상 메소드와 동일한 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야 한다. 이러한 객체를 인터페이스의 구현 객체라고 한다.

     

     

    구현 클래스는 다음과 같이 명시할 수 있다.

    public class 구현클래스명 implements 인터페이스명 {
     // 인터페이스에 선언된 추상 메소드의 실체 메소드를 선언


    implements 키워드를 통해서 사용하고자 하는 인터페이스를 명시해주면 된다.
    그리고 중괄호 내부에는 인터페이스에 선언되어 있는 추상 메소드들의
    오버라이딩한 실체 메소드들을 선언해주면 된다.

     

    실체 메소드를 작성할 때 주의할 점

    • 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 가지므로, public 보다 더 낮은 접근 제한으로 작성할 수 없다.
    • 만약 인터페이스에 선언된 추상 메소드에 대응하는 실체 메소드를 구현 클래스가 작성하지 않으면, 해당 구현 클래스는 자동적으로 추상 클래스가 된다.

     

     

    익명 구현 객체 : 일회성의 구현 객체를 만들기 위해 구현 클래스의 소스 파일을 만드는 것은 비효율적이므로, 소스 파일을 만들지 않고도 구현 객체를 만들 수 있는 방법

     

    자바는 UI 프로그래밍에서 이벤트를 처리하거나 임시 작업 스레드를 만들기 위해 익명 구현 객체를 많이 활용한다.

    인터페이스 변수 = new 인터페이스() {
        //인터페이스에 선언된 추상 메소드의 실체 메소드 선언
    };

    익명 구현 객체를 선언하는 법은 위와 같다.
    마치 클래스가 new 연산자를 통해 객체를 만드는 것과 같이 선언하는데,
    인터페이스는 생성자가 없으므로 "인터페이스()" 부분을 생성자라고 생각하면 안된다.
    단순히 형식만 같은 것이다.

    중괄호 블록 안에는 인터페이스에 선언된 추상 메소드의 실체 메소드를 선언해야 한다.
    그리고 가장 중요한 점은 반드시 끝에 세미콜론(;)이 붙어야 한다.

    익명 구현 객체도 자바 컴파일러에 의해서 클래스 바이트 코드 파일이 생성된다.

    파일 이름은 "~$번호.class" 의 형태로 익명 구현 객체가 선언된 순서에 따라 번호가 알아서 붙으며 생성된다.

     

     

    객체는 여러 인터페이스를 implements 할 수도 있다. 이것을 다중 인터페이스 구현 객체라고 한다,

    인터페이스 A와 B 이렇게 2개의 인터페이스가 있다고 할 때, 하나의 객체가 이 2개의 인터페이스 모두를 사용하려면 다음과 같이 작성해야한다.

    public class 구현클래스명 implements 인터페이스A, 인터페이스B {
        //인터페이스A에 선언된 추상 메소드의 실체 메소드 선언
        //인터페이스B에 선언된 추상 메소드의 실체 메소드 선언
    }

    하나의 객체가 두 개 이상의 인터페이스를 사용하려면
    객체 중괄호 내부에 두 개 이상의 인터페이스에 담긴 모든 추상메소드를 실체 메소드로 선언해야한다.

     


     

    3. 인터페이스의 사용


    인터페이스로 구현 객체를 사용하려면 인터페이스 변수를 먼저 선언하고, 그 곳에 구현 객체를 대입해야 한다.

    RemoteControl은 인터페이스이다.
    Television과 Audio는 RemoteControl을 implements 하는 구현 클래스이다.

    RemoteControl rc;
    rc = new Television();
    rc = new Audio();

    위와 같이 먼저 인터페이스 타입의 변수인 rc를 선언하고
    rc에 Televison이나 Audio의 객체를 대입해야 비로소 구현 객체를 사용할 수 있다.

     

    인터페이스의 추상 메소드를 구현 객체에서 실체 메소드를 작성했다면 그 사용법은 다음과 같다.

    RemoteControl rc = new Television();
    rc.turnOn();
    rc.turnOff();

    turnOn과 turnOff는 RemoteControl에 선언되어 있는 추상 메소드이고, Televison에서 오버라이딩 하였다.
    따라서 Television의 turnOn과 turnOff라는 메소드를 사용하기 위해서는 위 처럼 인터페이스 타입 변수에
    구현 객체를 대입하고 도트 연산자를 이용하여 사용할 수 있다.

     

    인터페이스의 정적 메소드는 바로 호출이 가능하기 때문에 구현 객체가 필요없다.

    RemoteControl.changeBattery();

    changeBattery는 RemoteControl 인터페이스에 선언된 정적 메소드이다.
    따라서 구현 객체를 대입할 필요없이, 인터페이스에서 바로 호출이 가능하다.

     


     

    4. 인터페이스의 상속과 확장


    인터페이스도 다른 인터페이스를 상속하는 것이 가능하다.

    인터페이스는 클래스와 다르게 다중 상속을 허용한다는 것이 특징이다.

    public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 {
     ....
    }

    하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라, 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 한다.

     

     

    디폴트 메소드가 있는 인터페이스를 상속할 때는 다음과 같은 세 가지 방법이 있다.

    1. 디폴트 메소드를 단순히 상속만 받는다.
    2. 디폴트 메소드를 오버라이딩해서 실행 내용을 변경한다.
    3. 디폴트 메소드를 추상 메소드로 재선언한다.

    여기서 잠깐!!!! 굳이 디폴트 메소드가 왜 있는 것일까?

    왜 자바 8부터 디폴트 메소드라는 개념이 등장했는지 알아보자!

     

    인터페이스에서 디폴트 메소드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다.

    자세한 이유는 다음과 같다.

    기존에 OneInterface와 OneClass가 있다고 가정해보자.
    OneClass는 OneInterface를 implements 하고 있다.

    그런데, 시간이 흘러서 OneInterface에 기능을 추가해야할 일이 생겼다고 해보자.
    그러면 만약 OneInterface에 새로운 기능이 담긴 추상메소드를 추가 선언하면 무슨 일이 일어날까?

    OneClass에서 에러가 날 것이다.

    왜냐하면 OneClass에는 OneInterface에 새로 만든 추상메소드에 대한 실체 메소드가 오버라이딩 되지 않았기 때문이다.

    즉, 인터페이스에 새로운 추상메소드를 추가하면 기존에 사용하던 구현 객체들이 실체 메소드를 가지고 있지 않아서 컴파일 에러가 난다. 이러한 이유로 디폴트 메소드의 필요성이 생겼다.

    새로운 기능을 추상메소드가 아니라 디폴트 메소드로 넣게 되면
    기존에 사용하던 구현 객체들은 컴파일 에러를 일으키지 않게 된다.
    또한 새로운 구현 객체가 등장하더라도 해당 디폴트 메소드를 오버라이딩하거나 그대로 사용할 수도 있다.

     

     

    본 게시글은 여기서 마치겠습니다.

    읽어주셔서 감사하고, 혹시나 틀린 부분이나 보완해야할 부분이 있다면 댓글에 남겨주세요~!

    댓글

Designed by Tistory.