Java

인터페이스

인터페이스란?

인터페이스(interface)는 다소 추상적인 개념이다. 인터페이스가 무엇인가를 철학적으로 논하려면 책 한권이 필요할지도 모르겠다. 하지만 우리는 철학 공부를 하는 것이 아니라 공학 공부를 하는 것이니 자바의 기능으로서 인터페이스를 받아들이면 되겠다.

필자가 앞선 수업에서 인터페이스를 abstract, final와 함께 대표적인 규제라고 언급했던 것 기억하는가? 인터페이스의 역할은 이렇다. 어떤 객체가 있고 그 객체가 특정한 인터페이스를 사용한다면 그 객체는 반드시 인터페이스의  메소드들을 구현해야 한다. 만약 인터페이스에서 강제하고 있는 메소드를 구현하지 않으면 이 에플리케이션은 컴파일 조차 되지 않는다.

예제

우선 단순한 예를 보자.

package org.opentutorials.javatutorials.interfaces.example1;

interface I{
    public void z();
}

class A implements I{
	public void z(){}
}

클래스 A 뒤의 implements I는 이 클래스가 인터페이스 I를 구현하고 있다는 의미다. 그것은 3행의 interface I의 맴버인 public void z() 메소드를 클래스 A가 반드시 포함하고 있어야 한다는 뜻이다. 따라서 위의 코드는 문제가 없다. 인터페이스의 의미를 좀 더 분명하게 하기 위해서 8행의 public void z(){}를 삭제하자. 컴파일 에러가 발생할 것이다. 

인터페이스와 상속은 다르다. 상속이 상위 클래스의 기능을 하위 클래스가 물려 받는 것이라고 한다면, 인터페이스는 하위 클래스에 특정한 메소드가 반드시 존재하도록 강제한다. 이러한 규제가 왜 필요한지는 뒤에서 알아본다.

또 사용하는 키워드도 다르다. 클래스를 선언 할 때는 class를 사용하지만 인터페이스는 interface를 사용한다.

또 상속은 extends를 사용하지만 인터페이스는 implements를 사용한다. 이를 바탕으로 위의 예제를 해설해보면 아래와 같다.

클래스 A는 인터페이스 I를 '구현' 한다.

실질적인 쓰임

계산기 예제에 인터페이스를 도입해보자. 계산기 기능이 필요한 프로젝트를 진행하는데 시간이 촉박하다. 그래서 계산기 클래스는 개발자 A가 만들고, 개발자 B는 그 클래스를 사용하는 로직을 만들다고 해보자. 이런 경우 개발자 B는 개발자 A가 계산기를 잘 만들어서 나중에 제출할 것이라고 기대하고 개발을 진행할 것이다. 그리고 아래와 같이 가짜 로직을 만들어서 코드를 작성했다.

package org.opentutorials.javatutorials.interfaces.example1;
class CalculatorDummy{
    public void setOprands(int first, int second, int third){}
    public int sum(){
        return 60;
    }
    public int avg(){
        return 20;
    }
}
public class CalculatorConsumer {
    public static void main(String[] args){
		CalculatorDummy c = new CalculatorDummy();
		c.setOprands(10,20,30);
		System.out.println(c.sum()+c.avg());
	}
}

개발자 A가 Calculator를 만드는데 3개월이 필요하다고 한다면 그 시간을 단축하기 위해서 위와 같은 코드를 작성하는 이유가 공감 할 수 있을 것이다. 3개월이 지나고 개발자 A가 Calculator 클래스를 완성해서 인계해줬다. 아래는 그 코드다.

package org.opentutorials.javatutorials.interfaces.example1;

class Calculator {
    int left, right;
	public void setOprands(int left, int right) {
		this.left = left;
		this.right = right;
	}
	public void sum() {
		System.out.println(this.left + this.right);
	}
	public void avg() {
		System.out.println((this.left + this.right) / 2);
	}
}

아뿔싸. 개발자 A는 setOprands의 매개변스를 2개 받고 있지만 개발자 B는 이 메소드가 변수 3개를 받을 것이라고 생각한 것이다. 이건 마치 해저터널의 공사가 중간에서 만나지 않은 것과 같은 상황이다. 이때부터 신경전이 시작된다. 경우에 따라서는 치열하게 다투게 되고 프로젝트는 파국으로 치닫는다. 이러한 문제를 해결하기 위한 가장 좋은 방법은 무엇일까? 협업자 상호간에 구체적인 약속을 하면 된다. 특히 그 약속을 코드 안에서 할 수 있다면 참 좋을 것이다. 그렇다. 인터페이스가 필요한 순간이다. 

클래스 Calculator를 사용할 개발자가 이 클래스가 가지고 있어야 할 메소드를 인터페이스로 만들어서 제공하는 것이다. 반대의 경우도 가능하다. 만드는 쪽에서 인터페이스를 제공하면 된다. 양쪽의 개발자는 이 인터페이스를 구현한 클래스 Calculator와 CalculatorDummy를 각각 구현하면 된다.

이렇게 해서 만들어진 코드를 보자. 아래는 약속을 정의하고 있는 인터페이스이다.

package org.opentutorials.javatutorials.interfaces.example2;

public interface Calculatable {
    public void setOprands(int first, int second, int third) ;
	public int sum(); 
	public int avg();
}

다음은 인터페이스를 구현한 가짜 클래스를 임시로 사용해서 만든 에플리케이션이다.

package org.opentutorials.javatutorials.interfaces.example2;
class CalculatorDummy implements Calculatable{
    public void setOprands(int first, int second, int third){
    }
    public int sum(){
        return 60;
    }
    public int avg(){
        return 20;
    }
}
public class CalculatorConsumer {
    public static void main(String[] args) {
		CalculatorDummy c = new CalculatorDummy();
		c.setOprands(10, 20, 30);
		System.out.println(c.sum()+c.avg());
	}
}

다음 코드는 인터페이스에 따라서 구현된 클래스이다.

package org.opentutorials.javatutorials.interfaces.example2;

class Calculator implements Calculatable {
    int first, second, third;
	public void setOprands(int first, int second, int third) {
		this.first = first;
		this.second = second;
		this.third = third;
	}
	public int sum() {
		return this.first + this.second + this.third;
	}
	public int avg() {
		return (this.first + this.second + this.third) / 3;
	}
}

이제 해야 할 일은 가짜 클래스인 CalculatorDummy를 실제 로직으로 교체하면 된다.

package org.opentutorials.javatutorials.interfaces.example2;
public class CalculatorConsumer {
    public static void main(String[] args) {
		Calculator c = new Calculator();
		c.setOprands(10, 20, 30);
		System.out.println(c.sum()+c.avg());
	}
}

이렇게해서 인터페이스를 이용한 협업에 대해서 알아봤다. 인터페이스를 이용해서 서로가 동일한 메소드를 만들도록 규약을 만들어서 공유한 결과 각자가 상대의 일정이나 구현하는 방식에 덜 영향을 받으면서 에플리케이션을 구축 할 수 있었다.

인터페이스의 규칙

인터페이스의 몇가지 규칙을 더 알아보자.

하나의 클래스가 여러개의 인터페이스를 구현 할 수 있다. 

클래스 A는 메소드 x나 z 중 하나라도 구현하지 않으면 오류가 발생한다.

package org.opentutorials.javatutorials.interfaces.example3;

interface I1{
    public void x();
}

interface I2{
	public void z();
}

class A implements I1, I2{
	public void x(){}
	public void z(){}	
}

인터페이스도 상속이 된다.

package org.opentutorials.javatutorials.interfaces.example3;

interface I3{
    public void x();
}

interface I4 extends I3{
	public void z();
}

class B implements I4{
	public void x(){}
	public void z(){}	
}

인터페이스의 맴버는 반드시 public이다.

아래 코드는 오류를 발생한다. 인터페이스는 그 인터페이스를 구현한 클래스를 어떻게 조작할 것인가를 규정한다. 그렇기 때문에 외부에서 제어 할 수 있는 가장 개방적인 접근 제어자인 public만을 허용한다. public을 생략하면 접근 제어자 default가 되는 것이 아니라 public이 된다. 왜냐하면 인터페이스의 맴버는 무조건 public이기 때문이다.

package org.opentutorials.javatutorials.interfaces.example3;

interface I5{
    private void x();
}

abstract vs interface

인터페이스와 추상 클래스는 서로 비슷한 듯 다른 기능이다. 인터페이스는 클래스가 아닌 인터페이스라는 고유한 형태를 가지고 있는 반면 추상 클래스는 일반적인 클래스다. 또 인터페이스는 구체적인 로직이나 상태를 가지고 있을 수 없고, 추상 클래스는 구체적인 로직이나 상태를 가지고 있을 수 있다.

댓글

댓글 본문
작성자
비밀번호
  1. 질문
    [실질적인 쓰임] 동영상에서 궁금한게 있습니다
    제가 아무리 생각해도 동영상의 저 상황에서 CalculatorDummy 클래스를 왜 굳이 만들어야하는지 모르겠습니다
    그냥 A가 Calculator를 만들어주면 B는 그때가서 사용법을 숙지한다음에 인스턴스를 생성해서 이용하면
    되는 것 아닌가요? 최종적으로는 Dummy클래스는 아예 사용하지 않는것 같은데,
    왜 굳이 Dummy를 만들어놔야 하는지 잘 이해가 안돼요

    실제로는 코드가 더 복잡하기때문에 Calculator클래스 사용법을 숙지하는데 기간이 오래 걸리는걸 줄이기 위해 Dummy클래스를 만드는건가요? 근데 그런거라면 Interface에 관련 내용이 이미 있어서 Interface만 참고해도 해결할 수 있는 문제인 것 같아서요
  2. 불확실
    가짜클래스와 진짜클래스가 인터페이스(중간역할)를 매개로 하여, 상호간 연동 된 상태로 각각 작업하며 인터페이스 약속에 근거하여 양측이 즉각적인 오류 체크가 가능하다는 정도로 와닿네요. 그러다가 문제 시 즉각적으로 오류가 뜨니 서로가 피드백 주고받아 공유문서 개념의 인터페이스를 수정해 주고 그렇게 해서 최종적으로 문제가 없을 시 사용자 측 메인메소드에 가짜클래스 이름으로 인스턴스화 되어 작업된 내용을 진짜클래스 이름으로 교체 적용한다 이정도만 생각이 드는데 맞는지는 잘 모르겠습니다. 어렵네요 ㅠㅠ
  3. 세현
    클래스는 다중상속이 불가하지만 인터페이스는 가능하네요
    ex)
    class A extends B,C {} -> 불가

    interface A extends B,C{} -> 가능
  4. cicada
    책으로 본건데 자바 8부터는 인터페이스에 디폴트 메소드, 정적 메소드형식으로
    메소드의 실체 즉 {}(중괄호)를 쓰는 메소드가 들어갈 수 있다고 합니다.

    비슷한점은
    둘다 추상 메소드로 꼭 들어가야할 메소드를 규약시킬 수 가 있을 뿐더러,
    스스로 객체 생성이 안되므로 따로 객체를 생성해줘야 멤버들을 쓸 수 있다는 점이 있겠구요.


    다른점은
    추상은 인터페이스와 달리 다중으로 적용이 안된다는 점과 생성자가 따로 존재해서 초기값 설정을 할 수 있고
    상수가 아닌 변수를 멤버로 가질 수 있는점이 있네요.

    쓰기에 따라 더 적합한 것을 쓰면 될 것같은데 그 기준점은 잘 모르겠네요.
  5. 감사합니다!!
  6. Weaver
    수업 감사합니다~~
  7. SK Kim
    후미 밑에 spam 테러...><
  8. JustStudy
    고맙습니다
  9. 임해
    댓글로 횟수 기록해둠 : 느낌
    2번 : 자바를 배우는 입장에서는 전혀 와닿지는 않음. 아마도 협업 때문에 그런 듯 합니다.
  10. 김트라슈
    감사합니다.
  11. somnium
    감사합니다~~
  12. 감사합니다~~
  13. 오빠는다르다
    감사합니다!!!!!
  14. 레니타키
    협업해서 일하는 환경이 아니라면 아직 와닿지 않을꺼 같네요. 인터페이스로 다른 작업그룹들을 강제시킨다는 개념정도로 이해하겠습니다.
  15. 두번째 동영상에서 Calculatorcustomer의 결과값은 90이아니라 80 아닌가요?? 별거아니지만ㅋㅋ..
  16. 박첩구드
    정말 중요한 개념같아요!! 처음 접하시는 분들은 어려운 개념일것 같아요 ㅠ
  17. 코코딩
    "아뿔싸. 개발자 A는 setOprands의 [매개변스]<---"

    오타 발견했습니다.
  18. cocohodu
    좋은강의 감사합니다
  19. 빛과소금
    인터페이스는 구체적인 로직이나 상태를 가지고 있을 수 없다고 하셨는데, 마커 인터페이스에 대해 공부할때 잘 이해가 안가네요..
  20. 최고영회
    public 으로 꼭 해야 하는 것이 아니라면 전부 다 private 으로 하시면 됩니다.
    그럼 무엇을 public 으로 해야 하는가?
    외부에서 직접 접근 가능한 method, field 에 대해서만 public 으로 하며
    일반적으로 변수들은 모두 private 으로 하고 public set/get method 를 통해 접근 하는 것이 더 좋습니다.
    대화보기
    • 지나가는 행인 1
      Interface와 Abstract Class는 목적이 다릅니다.
      인터페이스는 information hiding이 목적이고
      추상클래스는 polymorphism이 목적입니다.
      대화보기
      • 논맨
        잠깐 질문 하나 드려도 될까요. 초보적인 질문이긴한데요..
        어떤 의미에서는 추상클래스와 인터페이스가 목적이 비슷하다고 느껴집니다.
        추상클래스는 무조건 상속을 해야하는 경우(강제 상속을 통하여 해당 메소드를 쓰게 만듬(구현해야함))
        인터페이스는 자동으로 메소드를 생성해주어 (반강제로 메소드 사용(구현해야함))

        목적은 비슷하나 각각 쓰임새에 대한 장점이 있는거겠죠?

        *수정* 질문 쓰고 보니 강좌 마지막 문단을 읽었네요.
        인터페이스는 구체적인 로직이나 상태를 가지고 있을 수 없지만 추상클래스는 있다.
        그런데 와닿지가 않아서 질문드렸습니다 ㅠ
      • mary
        네네! 조금 더 심화해서 공부해보려고 했어요 ㅎㅎㅎ 이 강의엔 없는거죠? 이고잉님 강의가 제일 이해가 잘 되어서 혹시나 정리된 부분이 있나 했거든요! 아쉽네용 ㅠ_ㅠ 항상 잘 보고 있어요, 감사합니다!!!!
      • egoing
        초심자에게는 의미만 알면 되는 부분이예요~ 접근 제어자 같은거보다 반복문 조건문 같은 부분이 훨씬 중요하답니다! 소프트웨어가 거대해지면 필요한 기능입니다.
        대화보기
        • mary
          혹시 public과 private의 차이점이나 사용용도 등을 정리하신 파트가 어디인지 여쭤봐도 될까요? 의미는 알겠는데 어디에 써야할 지를 아직도 모르겠네요 ㅠㅠ
        • 쇠머리
          저에게도 평생 무료 강의 이용권 주셔서 너무~너무 감사드립니다.
          제 머리는 돌머리가 아닌 쇠대갈통이라 반복해서 들어도 무신 내용인지 알쏭달쏭~하거든요.
          그래두 반복~ 또 반복해서 들으니 이해가 서서히 됩니다.
        • 지나가는 인
          인터페이스의 맴버는 무조건 public의 methods 뿐인 것이죠?
          fields가 존재하면 어떤 상황에서 쓰이나요?
        • 환글
          저도 이제 겨우 배우는 입장이지만, 다른 강사분 말에 의하면 보통 Interface는 말 그대로 HW를 제어할 때 많이 사용한다고 합니다. 즉 HW는 이미 구현된 실체이므로 이것이 변경될 일이 거의 없다는 것이죠. 그래서 다중 상속을 허용하는 것 같아요.
          대화보기
          • 혜진소녀
            감사합니다~
          • 심비행기
            정말 최고입니다!
            감사합니다.
          • 과객
            좋은 강의 감사합니다.
          • 안녕하세요
            담아갈게요~ 감사합니다.
          • Junho Lee
            왜 자바는 인터페이스로만 다중상속을 하는건가요 ??
            혹시 이전 강의에서 언급하셨나요?? 필요한 부분만 찾아보다보니...
          • 헝그리
            3/3 동영상 마지막 부분에

            abstract vs interface 설명에서 동영상 보다가 잠시 헷갈렸네요.
            텍스트에는 수정이 되어있더라구요.

            이렇게 괄호로 되어있죠 동영상에. 공부하시는 분들 참고하세요.

            인터페이스와 추상 클래스는 서로 비슷한 듯 다른 기능이다. 인터페이스(인스턴스)는 클래스가 아닌 인터페이스(인스턴스)라는 고유한 형태를 가지고 있는 반면 추상 클래스는 일반적인 클래스다. 또 인터페이스(인스턴스)는 구체적인 로직이나 상태를 가지고 있을 수 없고, 추상 클래스는 구체적인 로직이나 상태를 가지고 있을 수 있다.

            화이팅!!
          • 헝그리
            강의 오른쪽에 이전 강의랑 다음 강의 리스트가 보이는데 중복되어 있어요.
            2/3 보고 순차 재생되는데 또 2/3 나와요

            오른쪽 밑에는 인터페이스 3/3이 보이네요.^^;;
          • egoing
            예? 동영상이 중복되는게 있나요? 살짝 보니까 서로 다른 동영상인 것 같은데요..
            대화보기
            • 헝그리
              강의 감사합니다!

              유튜브에 인터페이스 3/3 자리에 2/3 이 한개 더 있네요.ㅎㅎ
            • egoing
              그렇습니다! 선물로 평생 무료 강의 이용권을 드릴께요 ㅎㅎ 앞으로도 잘못된 부분 찾으면 알려주셔요!
              대화보기
              • 바보
                강의 잘보고 갑니다!

                근데 맨 밑에 인스턴스가 아니라 인터페이스 아닌가요~?ㅋ
              버전 관리
              egoing
              현재 버전
              선택 버전
              graphittie 자세히 보기