java/객체지향

20. 인터페이스(interface)

VanillaSky7 2023. 1. 25. 14:03

인터페이스(interface)?


인터페이스(interface)는 프로그래밍 관점과 보편적인 관점에서 이해할 수 있습니다. 이번 글에서는 프로그래밍 관점에 대해 먼저 다뤄

 

보도록 하겠습니다. 프로그래밍 관점에서의 인터페이스는 모두 접근 제어자 public으로 다뤄지는 추상 메서드들과 상수들을 묶어놓은

 

것을 의미합니다. 좀 더 정확하게는 static 메서드와 default 메서드들도 정의할 수 있지만, 두 메서드들에 대한 얘기는 보충글로 따로 빼서

 

다루겠습니다! 인터페이스도 추상 클래스와 마찬가지로 추상 메서드들을 포함하고 있기 때문에 추상 메서드들의 구현부를 구현해

 

주어야 합니다. 이번에는 인터페이스의 상속에 대해 얘기해보겠습니다. 인터페이스는 부모 혹은 조상은 또 다른 인터페이스만 가능합니다.

 

그 얘기는 Object 클래스가 자동으로 상속되지 않는 말이기도 합니다. 또한 인터페이스는 다중 상속이 가능합니다. 예를 들어 인터페이스

 

들 즉 인터페이스1, 인터페이스2를 다중 상속받는 어떠한 인터페이스3이 있다고 해보겠습니다. 이 인터페이스1과 인터페이스2에

 

같은 이름의 메서드가 있다고 하더라도 이 메서드들은 모두 추상 메서드들이므로 구현부가 없으므로 충돌할 일이 없기 때문에 다중 

 

상속이 가능한 것입니다! 또 다른 특징 한 가지 더! 상속받는 클래스는 상속과 동시에 구현을 할 수 있습니다.

 

class A extends B implements C              ← 부모 클래스 B를 상속받고 동시에 인터페이스 C를 구현할 수 있습니다.

 

(implements 키워드 및 구현이 무엇인지는 바로 밑 예제 설명에서 나옵니다!)

 

그럼 바로 예제를 통해 대략적으로 인터페이스에 대해 살펴보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
interface TempCalculator {
    // 항상 예외없이 상수만 선언가능하므로 public static final은 생략 가능!
    // 따라서 아래와 같은 형태들로 선언하더라도 자동으로 public static final이 붙음
    public static final int a = 1;
    static final int b = 2;
    final int c = 3;
    static int d = 4;
    int e = 5;
    
    // 메서드도 마찬가지로 예외없이 추상 메서드들만 선언 가능하므로 public abstract 생략 가능!
    // 따라서 두 번째, 세 번째 코드와 같은 형태로 선언하더라도 자동으로 public abstract가 붙음
    public abstract void getNumber(int a, int b);
    int sum();
    int subtraction();
}
 
class Calculator1 implements TempCalculator {
 
    int a;
    int b;
    
    public void getNumber(int a, int b) {
        this.a = a;
        this.b = b;
    }
 
    public int sum() {
        return this.a + this.b;
    }
    
    public int subtraction() {
        return this.a - this.b;
    }
}
cs

 

1행을 보시면 우선 클래스와 달리 인터페이스는 interface를 통해 선언됩니다. 즉 interface 인터페이스명 { } 과 같은 형태가 됩니다.

 

4행~8행을 보시면 기본적으로 인터페이스에는 예외없이 변수를 상수로만 선언되기 때문에 생략하더라도 public static final 이 

 

자동으로 붙습니다.

 

12행~14행도 마찬가지로 인터페이스에는 추상 메서드들로만 선언되므로 생략하더라도  public abstract 가 자동으로 붙습니다.

 

17행을 보시면 상속과 달리 extends 키워드를 사용하는 것이 아닌 implements 키워드를 사용하고, 이때 구현한다고 합니다.

 

22행, 27행, 31행과 같이 구체적으로 추상 메서드들을 구현해줄 때 유의할 점은 접근제어자입니다. 이전에 다뤘던 오버라이딩 글에서

 

오버라이딩 조건이 기억나시나요? 상속을 해준 클래스(부모 클래스)보다 접근제어자의 범위가 좁으면 안된다는 것입니다.

 

따라서 인터페이스를 구현해줄 때에는 public을 붙인다는 것에 주의하셔야 합니다!


인터페이스 vs 추상 클래스


바로 앞글에서 다룬 추상 클래스도 추상 메서드들 포함하는 미완성 설계도와 같은 역할을 하고, 인터페이스도 추상 메서드들을 포함하는

 

미완성 설계도라는 측면에서 얼핏보면 뭔가 둘이 같아보입니다. 그렇다면 둘에는 어떤 차이점이 존재할까요?

 

추상 클래스는 인스턴스 멤버(인스턴스 변수, 인스턴스 메서드), 생성자를 포함할 수 있습니다. 즉 일반적인  요소들을 모두 포함할 수 있고

 

추상 메서드들을 포함하는 정도가 일반적인 클래스와의 차이가 있습니다. 그러나 인터페이스는 이러한 일반적인 요소들은 포함시킬 수 

 

없고 상수 및 추상 메서드들만을 포함할 수 있습니다. (static 메서드, default 메서드도 포함할 수 있습니다. 보충글에서 다루겠습니다!)

 

인터페이스는 흡사 껍데기와도 같습니다. 이러한 껍데기와도 같은 역할이 어떠한 장점이 있는지는 바로 다음 글에서 다루겠습니다.


인터페이스와 다형성


우리가 앞서 다뤘던 다형성은 부모 타입의 참조변수로 자식 타입의 객체를 다루는 것이라는 것 기억나시나요?

 

인터페이스는 엄밀히 말해서 클래스가 아니므로 부모가 될 수는 없지만, 부모의 개념으로 생각할 수 있습니다!

 

따라서 인터페이스 타입의 참조변수로 자식 타입의 객체를 다루는 것이 가능합니다. 예를 들어 Animal이라는 인터페이스가 있고

 

이를 구현한 클래스 Dog가 있다고 가정했을 때 Animal A = new Dog(); 와 같이 작성이 가능합니다.

 

다음으로 상당히 중요한 것은 인터페이스 타입의 매개변수를 사용할 때에는 인터페이스를 구현한 클래스 인스턴스만 가능하다는

 

것입니다. void sound(Animal A); 이와 같은 코드가 있을 때 Animal 인터페이스를 구현한 클래스의 인스턴스만 들어올 수 있다는

 

의미입니다. 또한 인터페이스 또한 메서드의 리턴(반환) 타입으로 지정하는 것이 가능합니다.

 

1
2
3
4
5
6
7
8
Animal method() {
 
          중략
 
          Dog D = new Dog();
          return D;
 
}
cs

 

위 간단 코드와 같이 리턴 타입이 Animal 즉 인터페이스 타입으로 지정돼 있습니다. (한 문장으로 return new Dog(); 도 가능합니다!)

 

물론 이때 Dog 인스턴스이므로 Animal이라는 반환 타입과 일치하지는 않지만 Animal 인터페이스를 구현하고 있으므로 다형성으로 인해

 

가능한 것입니다! 좀 더 구체적으로 말씀드리자면 (Animal)로 형변환이 가능한 것인데 그 이유는 Animal 인터페이스와 Dog 인스턴스는

 

부모와 자식 관계이기 때문입니다. 이에 대한 이해는 예제를 참고해주세요! 여기서 중요한 포인트는 17행~24행 그리고 35행에서

 

타입 일치를 유의해서 살펴보시기 바랍니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.vanilla.javaStudy;
 
interface Animal3 {
    void sound();
    void intro(Animal3 A);
}
 
class Dog3 implements Animal3 {
    public void sound() {
        System.out.println("멍멍!");
    }
    
    public void intro(Animal3 A) {
        System.out.println("이 값이 담긴 주소는 " + A + " 입니다!");
    }
    
    Animal3 method() {
        Dog3 D = new Dog3();
        return D; // D 앞에는 (Animal3)가 생략돼 있음!
        
        // 다음과 같은 형태로도 작성 가능
        // Animal3 D = new Dog3();
        // return D;
    }
    
}
 
public class interfaceExam2 {
 
    public static void main(String[] args) {
 
        Dog3 D = new Dog3();
        D.sound();
        D.intro(D);
        Animal3 D2 = D.method();
        
    }
}
cs