[whiteship] 8주차 - 인터페이스

노력을 즐겼던 사람·2021년 1월 11일
0
post-thumbnail

학습할 것 (필수)

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

들어가기 앞서

6주차 때 상속을 공부하면서 우리는 자바에서 다중 상속이 불가능 한 것을 확인했다.
이는 우리가 구현하고 싶어하는 객체지향 프로그래밍에서는 상당한 제약사항이다.
자바를 개발한 사람들도 이 사실을 알고 있었지만 자바를 C++ 보다 더 안정적인 언어로 만들고 싶었다. 그를 위해 조금 덜 유연하게 설계 되었으며 더 적은 오류 발생을 보여준다.

이러한 제약 사항의 해결책으로 Interface를 선택했다.

인터페이스

interface는 클래스처럼 reference type이다.
이름에서 알 수 있듯이 API를 그저 표현하기만 한다.
다시 말하면 타입, 메소드, 클래스의 명세만 제공한다.

일반적으로 interfacebody를 작성하지 않는다. 그리고 interfaceimplementation하는 클래스는 메소드를 반드시 오버라이딩 해야한다.

이러한 특징 때문에 표준화가 가능하며 표준화를 통해 개발 시간 단축이 가능하다.
클래스간의 관계 매핑도 가능하다.

인터페이스 정의하기

interface Human {
    void hello();
    
    // Java8 부터 허용되는 default 키워드
    // 메소드의 구현체를 포함시킬 수 있다.
    default void sleep() {
        System.out.println("zzZZ");
    }
}

인터페이스의 특징

  • 정의된 메소드들은 암묵적으로 public abstract 메소드이다.
  • abstract 키워드를 작성해도 되지만 convention에 따라 생략한다.
  • interface의 멤버들은 암묵적으로 public이지만 컨벤션을 따라 생략한다.
  • interface는 인스턴스 필드를 선언할 수 없다.
    • 허용되는 필드는 static final 키워드가 함께하는 필드이다.
      즉, 클래스 필드만 허용한다는 뜻이다.
  • interface는 인스턴스화 시킬 수 없기 때문에 생성자를 정의하지 않는다.
  • 내부에 Nested Type을 포함할 수 있다. 이는 암묵적으로 public static 키워드를 가진다.
  • Java 8부터 static method를 포함할 수 있다. static method는 body를 추가해야한다.
  • Java 9부터 private method 를 포함할 수 있다.
    • 인터페이스 내에서만 사용이 가능하다. 따라서 메소드 바디를 구현해야 한다.
    • private static 메소드는 또 다른 static 메소드나 static 메소드가 아닌 곳에서는 사용할 수 없다.
    • 마찬가지로 non- static private 메소드는 private static에서 사용할 수 없다.
  • protected method를 선언하려고 하면 컴파일 에러가 발생한다.

인터페이스 상속받기

인터페이스는 다른 인터페이스를 여러개 상속 받을 수 있다.
클래스와는 다르게 다중 상속이 가능하다.

interface Life {
    // public static final 이 생략되어 있다.
    // 따라서 초기화하지 않으면 선언이 불가능하다.
    double breathInterval = 5;

    void breath();
}

interface Human extends Life {
    void hello();

    default void sleep() {
        System.out.println("zzZZ");
    }
}

부모 인터페이스의 default method는 오버라이딩이 가능하다.

인터페이스 구현하기

클래스는 하나 이상의 interfaceimplements 할 수 있다.

작성 규칙은 다음과 같다.

  • implementsextends 키워드 이후에 작성해야한다.
  • interface,로 구분한다
  • 클래스는 interface에 명시된 메소드들의 body를 구현해야 한다.
  • default method는 다시 구현할 필요가 없다.

단일 구현

public class American implements Human {
  @Override
  public void hello() {
    System.out.println("Hello");
  }
}


public class Korean implements Human {
  @Override
  public void hello() {
    System.out.println("안녕하세요");
  }
}

다중 구현

public interface Bug extends Life {
    String head = "머리입니다";
    String chest = "가슴입니다";
    String body = "배입니다";
}

public interface Plant extends Life {
    void photosynthesis();
}

public class Cordyceps implements Plant, Bug {
    @Override
    public void breath() {
        System.out.println("숨은 여름 겨울 둘 다 쉽니다~");
    }

    @Override
    public void photosynthesis() {
        System.out.println("여름엔 식물이라서 광합성합니다~");
    }

    public void insect() {
        System.out.println("겨울엔 곤충이라서 머리 가슴 배로 이루어져 있습니다~");
        System.out.println(head);
        System.out.println(chest);
        System.out.println(body);
    }
}

인터페이스 레퍼런스로 구현체 사용하기

Human korean = new Korean();
korean.hello();
korean.sleep();

Human american = new American();
american.hello();
american.sleep();

Human 인터페이스를 구현하고 있는 KoreanAmericanHuman 타입으로 생성될 수 있다. 이를 다형성이라고 한다.

이를 통해 어떤 메소드의 파라미터로 받을 수도 있다.

void test(Human human) {
	// TODO
}

...
...
...

test(korean);
test(american);

이런식으로 KoreanAmerican을 받기 위해서 오버로딩하지 않고 인터페이스를 구현하고 있는 녀석들로 매개변수를 받을 수 있다.

HumanLife의 자식 클래스이기 때문에 Life로도 받을 수 있다.

void test(Life life) {
	// TODO
}

...
...
...

test(korean);
test(american);

당연한 이야기지만 Life로 받는다면 Human에 정의된 메소드들은 사용할 수 없고 명시적으로 형변환을 통해서만 사용이 가능하다.

Human을 받는 testLife를 받는 test가 동시에 존재할 때 Human을 받는 test가 동작한다.

profile
노력하는 자는 즐기는 자를 이길 수 없다 를 알면서도 게으름에 지는 중

0개의 댓글