인터페이스

반응형
반응형

 

네트워크에서 인터페이스는 포트를 지칭하는 말이다. 즉, 인터페이스로 어떤것을 사용할지 알 수 있게 도와주는 역할을 한다.
자바에서도 마찬가지다.
일반적으로 인터페이스는 규약을 정의할때 사용이 되어진다.
그래서 직접 구현하는 것보다, 추상적으로 서로간의 "약속"을 정할때 사용된다.

그러면 인터페이스는 어떻게 만드는걸까?

간단히

public interface Interfaces {
}

class =>  interface로 바꿔주면 된다.

구현하는 방법은 크게 2가지가 존재하는데,

 다른 클래스에서 구현하는 방법

public abstract void hello();

로 구현해되지만
public abstract는 생략이 가능하다.

먼저 메소드 몇 개를 구현해보자.

public interface Interfaces {
    void hello();
    void well();
    void hwo();
}

위에서 언급했듯이 이 메소드를은 Interfaces라는 클래스를 사용하기 위한 약속이다.
다른 클래스는 어떤것을 뜻 할까?

     클래스

       클래스는 이 인터페이스를 이용한다라고 해석할 수 있다.

이런식으로 구현되어지는데, 우리는 이 약속들을 어떻게 해결할 것인지 명시해줘야한다.
이것을 구현한다고 말한다.

public class Clazz implements Interfaces{
    @Override
    public void hello() {
        
    }

    @Override
    public void well() {

    }

    @Override
    public void hwo() {

    }
}

우리는 이제 이 메소드를 구현을 해주면 된다.

인터페이스

만약, 인터페이스에 인터페이스를 상속을 시킨다면 어떻게 될까?

이렇게 했다는 것은 새로운 규약을 추가한다는 의미한다.

두 번째, 직접 구현하는 방법 

자바8이후 부터 인터페이스자체에서 인터페이스를 구현이 가능해졌다. 이것 때문에 다중상속이 불가능했던 자바도 다중 상속이 가능해졌다. 직접 구현이 가능하게 도와준 3가지를 소개하려고한다.

default 

default키워드를 이용하게 되면,
구현체를 만들 수 있다.

public interface Interfaces {
    default void doW() {
        System.out.println("hello");
    }
}

default의 특징은
타 패키지에서는 사용이 불가능하다는 것이 특징이다.
(이것보다 범위가 넒은 protected는 타 패키지에서 상속이 가능하다.)
그렇다는 뜻은 인터페이스에서는 이 메소드를 사용이 불가능하다는 이야기일까?

먼저 같은 패키지에서는 오버라이딩이 되는것을 확인 할 수 있다.

그렇다면 다른 패키지에서는 어떨까?

package study.whiteship.single;

import study.whiteship.homework8.Interfaces;

public class End implements Interfaces {
    @Override
    public void hello() {
        
    }

    @Override
    public void well() {

    }

    @Override
    public void hwo() {

    }

    @Override
    public void doW() {
        
    }
}

가능하다. 고로 접근지시자 default와는 다른 키워드임이 증명되었다.
따라서 이 default키워드는 "필수 규약"이라고 말 할 수 있을 것 같다.

static

default만 구현이 가능한것은 아니다.
static도 똑같이 사용이 가능하다.
default는 접근 지시자 default가 아니였듯이, 이번에도 우리가 아는 static이 아닐까?

public interface Interfaces {
    void hello();
    void well();
    void hwo();

    static void doW() {
        System.out.println("hello");
    }
}

우리가 아는 static이라면 클래스.메소드명이 가능해질 것이다.
확인해보자.

@Override
public void hwo() {
   Interfaces.doW();
}


이렇게 나온것으로봐서 우리가 아는 static인게 맞는 것 같다.
하지만 기존 static과 다른 점이 하나 존재한다. 그것은
다른 패키지에서는 사용이 불가능하다는 것이다.

결론적으로, interface static method는 우리가 아는 static처럼 사용되어지만, 다른 패키지에서는 사용이 불가능하다는 것을 알 수 있었다.

private

자바9에서 private메소드를 구현할 수 있게 되었다.
private의 가장 큰 특징은 다른 클래스에 접근이 불가능하다는 것인데..

역시나 불가능하였다. 그렇다면 언제 사용해야될까?

 그렇다는 이야기는 메소드를 구현해야된다는 것인데.....
메소드를 구현한다는 이야기는 deafult나 static을 이용해야된다는 뜻으로 해석되어진다.

default void howMany() {
    if(doW() == 2) {
          System.out.println("성공!");
          return;
      }
     System.out.println("실패");
}

 

마지막으로 합쳐보자.

public interface Interfaces {
    int version();
    boolean check(int n);

    default void howMany() {
        if(doW() == 1) {
            System.out.println("성공!");
            return;
        }
        System.out.println("실패");
    }
    private int doW() {
        System.out.println("hello");
        return (check(version()) ? 1 : 2);
    }

}
public class Clazz implements Interfaces{
    public static int a;


    @Override
    public int version() {
        return 1;
    }

    @Override
    public boolean check(int n) {
        return (version() == n);
    }
}
public static void main(String[] args) {
        Interfaces clazz = new Clazz();
        clazz.check(1);
        clazz.howMany();
}

대충 버전을 확인해서 값을 주입시켜주는 코드다.

인터페이스 사용

익명클래스로 만들기 

Interfaces interfaces = new Interfaces() {
         @Override
         public int version() {
             return 0;
        }

        @Override
        public boolean check(int n) {
            return false;
       }
};

익명 클래스로 만들시 구현이 되있지 않는 상태이므로 코드를 작성해줘야한다.
코드는 더럽?지만 자바파일을 만들지 않아 파일 관리 이점이 더 좋다.
이런 방식은 자바8이후부터 람다 식으로 변환이 가능 해졌다.(메소드가 1개일때만 가능! 위 코드는 메소드가 2개이므로 불가능!)

구현체로 만들기

Interfaces interfaces = new Clazz();

미리 자바파일로 상속받아 만드는 방식으로 
장점으로는 익명 클래스보다 깔끔하다는 느낌을 받는다.
하지만, 자바 파일을 관리가 번거로움이 존재한다.

여기서 다이나믹 디스패치가 발생하였다.

+) 인터페이스로 상수만들어서 사용하기(사용 금지)

public interface Interfaces {
    int A = 2;
    int B = 4;
}

이렇게 사용하면.

System.out.println(Interfaces.A);

이런식으로 사용이 가능하다.
하지만 이 방식은 위험하다.
왜냐하면 이것을 상속받는 다고 생각해보자.

public class Clazz implements Interfaces{
    static int A = 5;
}

그리고 값을 수정하였다.

public static void main(String[] args) {
    System.out.println(Interfaces.A);
    System.out.println(Clazz.A);
}

이들을 실행해보면,

이렇게 나온다.
Claszz에 있는 A값을 지운다면,

이렇게 나온다.
이 방식은 API에 혼동을 줄 여지가 있기 때문에 사용은 하지  않는것이 좋다고 한다.
또한, 인터페이스 목적이 어떻게 동작을 할것인지에 대한 규약을 작성하는 것이기 때문에 이러한 방식은
인터페이스와 맞지 않는다. 고로 인터페이스는 사용하면 안된다. 

참고)

 

7주차 과제 : 패키지

pacakge 키워드import 키워드클래스패스CLASSPATH 환경변수\-classpath 옵션접근지시자나름 TodoList를 작성하여 일정에 밀리지 않고 과제를 수행했다.특정한 날에 몰아서 하는 것보다 꾸준히 조금씩 하는

velog.io

 

'프로그래밍 언어 > 자바' 카테고리의 다른 글

예외 처리  (0) 2021.01.14
프록시  (0) 2021.01.04
인터페이스  (0) 2021.01.04
나만의 DI프로그램 만들기  (0) 2021.01.03
리플렉션  (0) 2021.01.01
Mockito 사용해보기  (0) 2020.12.31

댓글(0)

Designed by JB FACTORY