스터디할래 - 8주차 과제: 인터페이스

 https://github.com/whiteship/live-study

👍목표

 

자바의 인터페이스에 대해 학습하세요.

 

 

📖학습할 것 (필수)

 

 

  • 인터페이스 정의하는 방법
  • 인터페이스 구현하는 방법
  • 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
  • 인터페이스 상속
  • 인터페이스의 기본 메소드 (Default Method), 자바 8
  • 인터페이스의 static 메소드, 자바 8
  • 인터페이스의 private 메소드, 자바 9

 

 


인터페이스(interface)란?

 자바에서 인터페이스는 객체의 사용 방법을 정의한 타입이다. 인터페이스는 객체의 교환성을 높여주기 때문에 다형성을 구현하는 매우 중요한 역할을 한다. 

 

 인터페이스는 *.java 형태의 자바 소스 파일로 작성되고 컴파일러를 통해 *.class 형태로 컴파일 되기 때문에 물리적인 형태는 클래스와 동일하고 차이점은 선언하는 방식이 다르다.

 

 

인터페이스 정의하는 방법

 

[public] interface 인터페이스명 {
	// ...
}

public interface AccountService {
	public void login();
}

 

 클래스는 필드, 생성자, 메서드를 구성 멤버로 가지는 반면 인터페이스는 상수와 메서드 만을 구성 멤버로 가지며, 인터페이스는 객체로 생성할 수 없기 때문에 생성자를 가질 수 없다.

 


인터페이스 구현하는 방법

 

인터페이스의 메서드를 호출하면, 인터페이스는 객체의 메서드를 호출한다. 객체는 인터페이스에서 정의된 추상 메서드와 동일한 이름, 매개변수 타입, 반환 타입을 가진 실체 메서드를 가지고 있어야 한다. 

 

 이러한 객체를 인터페이스의 구현(implement) 객체라고 한다. 구현 객체를 생성하는 클래스를 구현 클래스라 한다.

 

 

public interface AccountService {
	public void login();
}

// AccountService를 구현하는 클래스

public class AccountServiceImpl implements AccountService {
	
    @Override
    public void login() {
      // Todo: 구현코드 작성
    }
}

 

인터페이스 레퍼런스를 통해 구현체를 사용하는 방법

 

인터페이스로 구현체를 사용하려면 다음과 같이 인터페이스 변수를 선언하고 구현체를 대입해야 한다. 인터페이스 변수는 참조 타입이기 때문에 구현체가 대입 될 경우 구현체의 주솟값을 저장한다. 

 

OrderService.java
public interface OrderService {
    public void cancel();
}

 

CardOrder.java
public class CardOrder implements OrderService {
    @Override
    public void cancel() {
        System.out.println("카드 주문 취소");
    }
}

 

CashOrder.java
public class CashOrder implements OrderService {
    @Override
    public void cancel() {
        System.out.println("현금 주문 취소");
    }
}

 

OrderServiceTest.java
class OrderServiceTest {
    @DisplayName("인터페이스 구현체 대입 테스트")
    @Test
    void interfaceTest() {
        OrderService orderService = new CardOrder();
        orderService.cancel();

        orderService = new CashOrder();
        orderService.cancel();

    }
}

Output:
카드 주문 취소
현금 주문 취소

 

 취소(cancel) 기능만 존재하는 OrderService 인터페이스와 OrderService 인터페이스를 구현한 두 개의 구현체 CashOrder와 CardOrder를 정의 하였고 테스트 하였다.

 

 OrderService를 테스트 하기 위한 OrderServiceTest에서 CardOrder를 구현체로 하는 인터페이스 변수를 선언하고, Cancel메서드를 호출 후, orderService의 구현체를 CashOrder로 갈아 끼웠다(교체 했다).

 

다시 cancel 메서드를 호출하였으며 출력 결과는 CardOrder에서 구현한 cancel의 동작을 수행 후, 갈아 끼운 CashOrder의 cancel이 동작한 것을 확인 할 수 있다.

 

 

인터페이스 상속

 

인터페이스도 다른 인터페이스를 상속할 수 있다. 인터페이스는 클래스와 달리 다중 상속이 가능하다는 특징이 있으며, 클래스와 마찬가지로 인터페이스의 상속 시에는 인터페이스 명 뒤에 extends를 붙여준다.

 

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

 

public interface InterfaceA {
	public void methodA();
}

 

public interface InterfaceB {
	public void methodB();
}

 

public interface InterfaceC extends InterfaceA, InterfaceB {
	public void methodC();
}

 

public class ImplementC implements InterfaceC {
    public void methodA() {
    	System.out.println("methodA()");
    }
    public void methodB() {
    	System.out.println("methodB()");
    }
    public void methodC() {
    	System.out.println("methodC()");
    }
}

 

public class Main {
    public static void main(String[] args) {
        ImplementC implementC = new ImplementC();

        InterfaceA interfaceA = implementC;
        interfaceA.methodA();

        InterfaceB interfaceB = implementC;
        interfaceB.methodB();

        InterfaceC interfaceC = implementC;
        implementC.methodA();
        implementC.methodB();
        implementC.methodC();
    }
}
output:
methodA()
methodB()
methodA()
methodB()
methodC()

 

InterfaceA와 InterfaceB를 상속받은 InterfaceC를 구현한 ImplementC 클래스이다. 

 

InterfaceA 객체에 ImplementC 구현체를 대입하면 InterfaceA에 정의한 메서드만 실행이 가능하지만, InterfaceC는 InterfaceA, B에서 선언한 메서드 모두 호출 가능하다.


인터페이스의 기본 메소드 (Default Method), 자바 8

 

 자바8에서는 인터페이스에 defalut method를 지원하는데, 인터페이스에 선언된 인스턴스 메서드이기 때문에 구현체가 있어야 사용할 수 있다. 선언은 인터페이스에서 하고 사용은 구현체를 통해 한다.

 

 디폴트 메서드는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해 사용되며 기존 인터페이스의 이름과 추상 메서드의 변경 없이 디폴트 메서드만 추가할 수 있기 때문에 이전에 개발한 구현 클래스를 그대로 사용할 수 있으면서 새롭게 개발하는 클래스는 디폴트 메서드를 활용할 수 있다.

 

 

public interface InterfaceA {
    public void methodA();
    public default void defaultMethodA() {
        System.out.println("Default Method A in InterfaceA");
    }
}

 

public class ClassA implements InterfaceA {
    @Override
    public void methodA() {
        System.out.println("methodA in ClassA");
    }

}

 

public class ClassB implements InterfaceA {
    @Override
    public void methodA() {
        System.out.println("MethodA in ClassB");
    }

    @Override
    public void defaultMethodA() {
        System.out.println("Default Method in ClassB");
    }
}

 

public class Main {
    public static void main(String[] args) {
        InterfaceA interfaceA = new ClassA();
        interfaceA.methodA();
        interfaceA.defaultMethodA();

        interfaceA = new ClassB();
        interfaceA.methodA();
        interfaceA.defaultMethodA();
    }
}

Output:
methodA in ClassA
Default Method A in InterfaceA
MethodA in ClassB
Default Method in ClassB

 

인터페이스에서 정의한 Default method는 재정의하지 않을 경우, 기존 인터페이스에서 정의한 메서드가 사용되고, 다른 구현체에서 재정의해서 구현한 메서드를 사용할 경우 재정의된 메서드를 호출하는 것을 확인할 수 있다.

 

인터페이스의 static 메소드, 자바 8

 

Default method 외에도 자바8에서는 static method를 지원한다. static method의 특징으로는 재정의가 불가능하며, default method와 마찬가지로 인터페이스 내에서 구현 가능하다.

 

public interface InterfaceA {
    public void methodA();
    public default void defaultMethodA() {
        System.out.println("Default Method A in InterfaceA");
    }
    public static void staticMethod() {
        System.out.println("Static method in InterfaceA");
    }
}


인터페이스의 private 메소드, 자바 9

 

자바9에서는 private method 를 지원하며 static method와의 사용이 가능하지만, default 키워드를 추가할 경우 

 

"Illegal combination of modifiers: 'default' and 'private' 이라는 에러 메시지를 출력하는 것을 볼 수 있다.

 

 

 

References

이것이 자바다(신용권 저)
TCP School