티스토리 뷰

인터페이스

  • 일종의 추상 클래스
  • 추상클래스와 달리 일반 메서드를 멤버로 가질 수 없음.
    -JDK1.8부터 등장한 static 메서드, default 메서드는 예외

인터페이스 정의하는 방법

interface 인터페이스이름 {
    public static final 타입 상수이름 = 값;
    public abstract 메서드이름(파라미터목록);
}
  • 모든 멤버변수는 public static final 로 선언. (생략 가능)
  • 모든 메서드는 public abstract 로 선언. (생략 가능)
    • JDK1.8부터 등장한 static 메서드, default 메서드는 예외

인터페이스 구현하는 방법

  • 인터페이스는 추상클래스와 마찬가지로 그 자체로 인스턴스를 생성할 수 없음
  • 자신이 정의한 추상메서드의 body를 만들어주는 클래스를 작성해야 함.
    class 클래스이름 implements 인터페이스이름{
      //인터페이스에 정의된 추상메서드를 구현
    }
    
```java
public class FighterTest {
}
class Fighter extends Unit implements Fightable {
    @Override
    public void attack(Unit u) {
        //생략    
    }

    @Override
    public void move(int x, int y) {    //반드시 public
        //생략
    }
}
interface Fightable extends Movable, AttackAble{
}
interface Movable {
    void move(int x, int y);
}

interface AttackAble {
    void attack(Unit u);
}

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

  • 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 담을 수 있다.
  • 인터페이스 타입의 참조변수로 해당 인터페이스를 구현한 클래스의 인스턴스를 담을 수 있다.
  • 인터페이스 타입의 파라미터
    • 해당 인터페이스를 구현한 클래스의 인스턴스를 파라미터로 제공해야 함을 의미
  • 인터페이스 타입의 리턴타입
    • 해당 인터페이스를 구현한 클래스의 인스턴스를 반환해야 함을 의미
public class ParserTest {

    public static void main(String[] args) {
        Parseable parser = ParseManager.getParser("XML");
        parser.parse("doc.xml");
        parser = ParseManager.getParser("HTML");
        parser.parse("doc.html");
    }

}

interface Parseable{
    void parse(String fileName);
}

class ParseManager{
    public static Parseable getParser(String type) {
        if (type.equals("XML")) {
            return new XMLParser();
        } else {
            return new HTMLParser();
        }
    }
}

class XMLParser implements Parseable {
    @Override
    public void parse(String fileName) {
        System.out.println(fileName + " XML parsing complete");
    }
}

class HTMLParser implements Parseable {
    @Override
    public void parse(String fileName) {
        System.out.println(fileName + " HTML parsing complete");
    }
}
  • 위 코드에서 만약 XMLParser 를 NewXMLParser로 바꾸고 싶다면? ParserTest 의 클라이언트 코드는 전혀 바꿀 필요가 없이 NewXMLParser를 구현한 후, return new XMLParser() -> return new NewXMLParser() 로 바꾸면 된다.

인터페이스 상속

  • 오직 인터페이스로부터만 상속 가능
  • 클래스와 달리 다중 상속 가능
  • 클래스의 상속과 마찬가지로, 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속 받음

인터페이스 사용 예시

  • 서로 관계없는 클래스들에게 관계를 맺어줄 때

    스크린샷 2022-02-04 오전 7 13 18
  • 직접적인 두 클래스 간의 관계를 간접적인 관계(의존적이지 않은 관계)로 변경할 때. 혹은 강한 결합을 느슨한 결합으로 바꾸고자 할 때.

    public class InterfaceTest2 {
      public static void main(String[] args) {
          A a = new A();
          a.autoPlay(new B());
          a.autoPlay(new C());
      }
    }
    class A {
      void autoPlay(I i) {
          i.play();
      }
      /*
      void autoPlay(B b){
          b.play();
      }
       */
    }
    interface I {
      public abstract void play();
    }
    class B implements I {
      @Override
      public void play() {
          System.out.println("B.play");
      }
    }
    class C implements I {
      @Override
      public void play() {
          System.out.println("C.play");
      }
    }

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

  • 자바8 이전에는 인터페이스에 메소드를 하나 추가한다는 것은, 추상 메서드를 만드는 일이었고 이는 해당 인터페이스를 구현한 모든 클래스가 추가된 메소드를 구현해야 함을 의미했다. 즉, 매우 번거롭고 복잡한 일이었다.
  • 자바8부터 추가된 디폴트 메소드는 추상 메소드의 기본적인 구현을 제공한다. 따라서 디폴트 메소드를 새로 추가하더라도 해당 인터페이스를 구현한 클래스들을 변경할 필요가 없다.
interface MyInterface {
    void method();
    default void newMethod(){}
}
public class DefaultMethodTest {
    public static void main(String[] args) {
        Child c = new Child();
        c.method1();    //Child.method1
        c.method2();    //Parent.method2
    }
}
class Child extends Parent implements MyInterface, MyInterface2{
    @Override
    public void method1() {
        System.out.println("Child.method1");    //Interface 간 default method 충돌 해결
    }
}
class Parent {
    public void method2() {
        System.out.println("Parent.method2");    //Interface - 조상 클래스 간 method 충돌시 우선 순위를 가짐
    }
}
interface MyInterface{
    default void method1() {
        System.out.println("MyInterface.method1");
    }

    default void method2() {
        System.out.println("MyInterface.method2");
    }

    static void staticMethod() {
        System.out.println("MyInterface.staticMethod");
    }

}
interface MyInterface2 {
    default void method1() {
        System.out.println("MyInterface2.method1");
    }

    default void staticMethod() {
        System.out.println("MyInterface2.staticMethod");
    }
}
  • default 메소드 네이밍 충돌 -> default 메소드를 오버라이딩
  • default 메소드 - 조상 클래스 메소드 네이밍 충돌 -> 조상 클래스의 메소드가 우선순위를 갖는다. 즉, default 메소드는 무시된다.

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

Static 메소드는 인스턴스와 관계가 없는 독립적인 메소드이기 때문에 인스턴스에 추가하지 못할 이유가 없었음. -> JDK1.8 부터는 인스턴스에 static 메소드 추가 가능

  • static 메서드의 접근 제어자는 항상 public. -> 생략 가능
  • 참고로, Collection 인터페이스 - Collections 클래스가 있다. 만약 자바가 처음부터 인터페이스에 static 메소드를 제공했다면, Collections 클래스는 만들어지지 않았을 것.

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

  • 인터페이스 내부에서 코드 재사용성 향상
  • 규칙
    • private 메소드는 추상 메소드로 선언 불가
    • 해당 인터페이스 내부에서만 사용 가능
    • private static 메소드는 해당 인터페이스 내부 static, non-static 메소드에서 사용 가능
public class InterfacePrivateMethodTest {
}

interface CustomInterface {

    default void method1() {
        method3();    //private method 호출
        method4();    //private static method 호출
    }

    static void method2() {
        method4();    //private static method 호출 가능
        System.out.println("static method");
    }

    private void method3() {
        System.out.println("private method");
    }

    private static void method4() {
        System.out.println("private static method");
    }
}

백기선님 리뷰 영상

  • Spring HandlerInterceptor

    • java8 이후 Interface - 구현 클래스 사이에 추상 클래스를 넣을 필요가 없어짐.
    • default 메소드를 이용해 반드시 구현하지 않아도 되는 메소드를 추가할 수 있기 때문
  • default 메소드 사용시 diamond inheritance 문제 해결 방법

    • Interface이름.super.메소드명 으로 해결
  • 추상 클래스 - 인터페이스 관계

    • 추상 클래스 : is-a
    • 인터페이스 : has-a
  • 추상 클래스의 필요성?

    • 추상 클래스에서 제공하는 것을 인터페이스에서 모두 구현할 수 있는가?
      • No.
      • e.g. private 필드 변수 & setter 는 추상 클래스에서만 사용 가능.
  • 함수형 인터페이스

  • 강한 결합, 느슨한 결합

    • 인터페이스를 쓰는 이유
    • 느슨한 결합을 해야(인터페이스를 쓰면) 코드를 바꿔끼기 좋다. 클라이언트 코드를 수정할 필요가 없음

References

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/01   »
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
글 보관함