[Java-OOP6] 인터페이스

이용준·2022년 10월 31일
0

Java

목록 보기
18/29

1.인터페이스란?

  • 객체를 어떻게 구성해야 하는지 정리한 설계도이다.
  • 인터페이스 변수에 인터페이스가 구현된 서로 다른 구현 객체를 할당해 가용 가능하다.
  • 구현 객체를 직접 몰라도 인터페이스 메서드만 알면 객체 호출이 가능하다.
  • 예제코드
(설계도)
동물원에 사육사가 있다.
육식 동물이 오면 먹이를 던져준다.
호랑이에게는 사과를, 사자에게는 바나나를 던져준다.
---
class Animal{
  String name;
  
  void setName(String name){
    this.name = name;
  }
}

class Tiger extends Animal{
}
class Lion extends Animal{
}

class ZooKeeper{
  void feed(Tiger tiger){//호랑이한테는 사과를 던져준다. +Call by value
    System.out.println("feed apple");
  }
  
  void feed (Lion lion){//사자한테 바나나를 준다.
    System.out.println("feed banana");
  }
}  
  
public class Sample{
  public static void main(String[] args){
    ZooKeeper zooKeeper = new ZooKeeper();
    Tiger tiger = new Tiger();
    Lion lion = new Lion();
    zooKeeper.feed(tiger);  // feed apple
    zookeeper.feed(lion);  //feed banana
  }
}  

이제 호랑이는 사과를, 사자는 바나나를 받게 되었다.
동물원에 동물이 둘 뿐이라면 사육사는 할 일이 없겠지만, 육식 동물이 추가된다면 매번 feed 메소드를 추가해야 한다. 이런 번거로움을 극복하기 위해서는 인터페이스의 도움이 필요하다.

2.인터페이스 작성하기

  • 예제 코드에 육식동물(Predator) 인터페이스를 추가해보자.
interface Predator{ // 인터페이스는 class가 아닌 interface로 작성한다.
}

class Animal{
  String name;
  
  void setName(String name){
    this.name=name;
  }
}
(...)

통상 인터페이스 역시 클래스처럼 단독 파일로 저장하는 것이 일반적이나, 
지금은 편의를 위해 파일의 최상단에 작성한다.
  • (Impelement)Tiger, Lion 클래스에 인터페이스가 구현되도록 수정한다.
(...)
class Tiger extends impelements Predator{
}
class Lion extends impelements Predator{
}

(...)

육식동물(Tiger, Lion) 클래스가 Predator 인터페이스를 구현하면 ZooKeeper 클래스의 feed 메소드를 다음과 같이 변경할 수 있다.

(변경전)
(...)
class ZooKeeper{
  void feed(Tiger tiger){
    System.out.println("feed apple");
  }
  void feed(Tiger tiger){
    System.out.println("feed apple");
  }
 (...) 

(변경후)
(...)
class ZooKeeper{
  void feed(Predator predator){
    System.out.println("feed apple");
  }
(...)
  • tiger - Tiger 클래스의 객체 / Predator 인터페이스의 객체
  • Lion - Lion 클래스의 객체 / Predator 인터페이스의 객체

이처럼 객체가 한 개 이상의 자료형 타입을 갖게 되는 특징을 다형성(폴리모피즘)이라 한다.

이 때 동물별 먹이는 어떻게 처리할 지 알아보도록 하자.

3.인터페이스의 메소드

작성한 코드에서 호랑이는 사과, 사자는 바나나를 받아야 한다.
이를 인터페이스를 통해 변경해보자.

interface Predator{
  String getFood();
}
(...)

위 인터페이스 메소드는 이름과 입/출력 정의만 있을뿐 내용은 없는 것을 볼 수 있다. 그 이유는 인터페이스는 규칙이기 때문이다.
getFood 메소드는 인터페이스를 implements한 클래스들이 구현해야만 한다.

인터페이스에 메소드를 추가하기 위해서는 다음처럼 Tiger, Lion 클래스에 getFood 메소드를 구현해야 한다.
(인터페이스 메소드는 항상 public으로 구현해야 한다.)

(...)
class Tiger extends Animal impelements Predator{
  public String getFood(){
  	return "apple";
  }
}
class Lion extends Animal impelements Predator{
  public String getFood(){
    return "banana";
  }
}  
(...)

이제 ZooKeeper 클래스도 다음처럼 변경이 가능하다.

(...)
class ZooKeeper{
  void feed(Predator predator){
    System.out.println("feed"+predator.getFood());
  }
}  
(...)

predator.getFood()를 호출하면 Predator 인터페이스를 구현한 구현체(Tigert, Lion)의 getFood()메소드가 호출된다.

4.인터페이스의 핵심과 개념

1) 위 과정을 통해 ZooKeeper 클래스가 동물들의 종류에 의존적 클래스에서 동물의 종류와 상관없는 독립적인 클래스가 되었다는 점을 알 수 있었으며, 바로 이 점이 인터페이스의 핵심인 것이다.

2) 인터페이스는 상속과 다른 점은 "강제성"을 지닌다는 점인데, 이는 상속에서 자식 클래스가 부모 클래스를 오버라이딩하지 않고 사용할 수 있기에 해당 메소드를 반드시 구현하는 "강제성"을 갖지 못하기 때문이다.

5.디폴트 메서드

인터페이스의 메서드는 몸통(구현체)를 가질 수 없지만 디폴트 메서드를 사용하면 실제 구현된 형태의 메서드를 가질 수 있다.
예를들어 Predator 인터페이스에 다음과 같은 디폴트 메서드를 추가할 수 있다.

interface Predator{
  String getFood();
  
  default void printFood(){ //default 표기해야 함
    System.out.printf("my food is %s\n", getFood());
  }
}

디폴트 메서드는 default로 표기해야 한다.
위처럼 Predator 인터페이스에 printFood 디폴트 메서드를 구현하면 Predator 인터페이스를 구현한 Tiger,Lion 등의 실제 클래스는 printFood 메서드를 구현하지 않아도 사용할 수 있다. 마지막으로 디폴트 메서드는 오버라이딩이 가능하다.(즉, printFood 메서드를 실제 클래스에서 다르게 구현할 수 있다.)

6.스태틱 메서드

인터페이스에 스태틱 메서드를 구현하면 인터페이스명.스태틱메서드명과 같이 사용해 일반 클래스의 스태틱 메서드를 사용하는 것과 동일하게 사용할 수 있다.

  • 예시) Predator 인터페이스에 스태틱 메서드 추가하기
interface Predator{
  String getFood();
  
  default void printFood(){
    System.out.printf("my food is %s\n", getFood());
  }

  int LEG_COUNT = 4; // 인터페이스 상수
  
  static int speed(){
    return LEG_COUNT * 30;
  }
}  

이렇게 스태식 메서드를 추가하면 다음과 같이 사용할 수 있다.

Predator.speed();
profile
뚝딱뚝딱

0개의 댓글