관리 메뉴

보리차

chapter 17 인터페이스와 추상 클래스 본문

Java

chapter 17 인터페이스와 추상 클래스

보리콩 2022. 2. 6. 21:42

추상 메소드만 담고 있는 인터페이스

추상 메소드(Abstract Methods): 몸체가 비어있는 메소드

 

인터페이스의 기본 골격은 클래스와 동일하다. 

interface Printable {    
    public void print(String doc);    // 추상 메소드
}

인터페이스를 대상으로는 인스턴스 생성이 불가능하다. 다만 다른 클래스에 의해 상속 될 뿐이다.

class Printer implements Printable {  
	@Override			// 오버라이딩 관계 성립
    public void print(String doc) {    // Printable 인터페이스의 print 메소드 구현
        System.out.println(doc);
    }
}

클래스가 인터페이스를 상속하는 행위는 '상속'이 아닌 '구현(Implementation)'이라 한다. 문법관계는 상속과 동일하지만 본질은 '구현'이기 때문이다.

 

클래스의 인터페이스 구현에는 다음과 같은 특징이 있다.

  • 구현할 인터페이스를 명시할 때는 키워드 implements를 사용한다.
  • 한 클래스는 둘 이상의 인터페이스를 동시에 구현할 수 있다.
  • 상속과 구현은 동시에 가능하다.
  • 인터페이스의 형을 대상으로 참조변수의 선언이 가능하다.
  • 인터페이스의 추상 메소드와 이를 구현하는 메소드 사이에 오버라이딩 관계가 성립한다.
class PrintableInterface {
    public static void main(String[] args) {
        Printable prn = new Printer();     // Printable형 참조변수 선언 가능
        prn.print("Hello Java");
    }
}

인터페이스의 의미

인터페이스의 뜻은 둘 사이를 연결하는 매개체로 자바의 인터페이스도 매개체 역할을 한다. 

 

 예를 들어 마이크로소프트의 윈도우가 삼성과 LG의 프린터를 대상으로 출력할 진행할 수 있다고 할 때, 마이크로소프트는 print에 대한 인터페이스만 제공하고 print 메소드는 회사별로 각자 구현해서 가져오게 된다. 그러면 마이크로소프트는 출력할 문서의 정보를 인자로 전달할 때 클래스 이름만 알면 될 뿐 내부적으로 구현이 어떻게 이뤄지는지는 알 필요가 없어진다.

 

 

인터페이스의 문법 구성과 추상 클래스

인터페이스의 모든 메소드는 public이 선언된 것으로 간주한다. 때문에 인터페이스 정의에서 메소드 앞에 public을 붙일 필요가 없다.

interface Printable {
    int PAPER_WIDTH = 70;    // 변수선언가능
    int PAPER_HEIGHT = 120;
    void print(String doc);    // public이 선언된 것으로 간주.
}

인터페이스에도 변수를 선언할 수 있다. 다만, 

  • 반드시 선언과 동시에 값으로 초기화 해줘야 하고
  • 모든 변수는 public, static, final 이 선언된 것으로 간주한다.

인터페이스를 구현하는 클래스는 인터페이스에 존재하는 모든 '추상 메소드'를 구현해야 한다.

 

인터페이스 간 상속

인터페이스 사이에도 상속이 가능하고, 이를 명시할 때 extends를 사용한다.

  • 두 클래스 사이의 상속은 extends로 명시한다.
  • 두 인터페이스 사이의 상속은 extends로 명시한다.
  • 인터페이스와 클래스 사이의 구현만 implements로 명시한다.

인터페이스의 디폴트 메소드

모든 인터페이스에 최소 한 개 이상의 추상 메소드를 추가해야 하는 상황이 벌어질 때 이 상황이 문제를 '인터페이스의 상속'으로 해결하게 되면, 인터페이스의 수는 두 배로 늘어나게 된다. 이런 상황의 해결을 위해 인터페이스의 '디폴트 메소드'라는 것이 자바 8에서 소개되었다.

 

interface Printable {
    void print(String doc);
    default void printCMYK(String doc) {...}    // 디폴트 메소드
}

디폴트 메소드

  • 자체로 완전한 메소드이다.
  • 따라서 이를 구현하는 클래스가 오버라이딩 하지 않아도 된다.

이렇듯 디폴트 메소드는 인터페이스에 추상 메소드를 추가해야 하는 상황에서 이전에 개발해 놓은 코드에 영향을 미치지 않기 위해 등장한 문법이다. 처음 인터페이스를 설계하는 과정에서 디폴트 메소드를 정의해 넣는다면 디폴트 메소드를 잘못 사용하고 있는 것이다.

인터페이스의 stastic 메소드(클래스 메소드)

  • 인터페이스에도 static 메소드를 정의할 수 있다.
  • 인터페이스의 static 메소드 호출 방법은 클래스의 static 메소드 호출 방법과 같다.

인터페이스 대상의 instanceof 연산

if(ca instanceof Cake) ...

ca가 Cake를 직접 혹은 간접적으로 구현한 클래스의 인스턴스인 경우 true를 반환한다.

Marker Interface

interface Upper { }  // 마커 인터페이스
interface Lower { }  // 마커 인터페이스

interface Printable {...}
 
 class Report Implements Printable, Upper {...}
 
 class Printer {
 	public void printContents(Printable doc) {
    	if(doc instanceof Upper) {...}		// doc 참조 인스턴스가 Upper 구현한다면
        else if(doc instanceof Lower) {...}	// doc 참조 인스턴스가 Lower 구현한다면
    }
}

예제에서 인터페이스 Upper와 Lower는 클래스에 붙이는 표식으로 사용되었다.

추상 클래스(Abstract Class)

하나 이상의 메소드를 갖는 클래스

public abstract class House {    // 추상 클래스
    public void methodOne() {
        System.out.println("method one");
    }
      public abstract void methodTwo();    // 추상 메소드
}
  • 추상 클래스는 클래스 선언부에 abstract 선언을 추가해야 한다.
  • 추상 클래스를 대상으로 인스턴스 생성이 불가능하고 다른 클래스에 의해서 추상메소드가 구현이 되어야 한다. (추상 클래스는 성격이 인터페이스와 유사)
  • 그럼에도 불구하고 이는 클래스이다. 따라서 구현의 형태가 아닌 상속의 형태를 띈다. (extends 사용)

 

클래스처럼 인스턴스 변수와 인스턴스 메소드를 갖지만, 이를 상속하는 하위 클래스에 의해서 구현되어야 할 메소드가 하나 이상 있는 경우를 '추상 클래스'라 한다.