본문 바로가기

개발/Language

Kotlin - 인터페이스 default 메서드

 

Kotlin에서는 인터페이스에 default 메서드를 제공한다.

 

 

Java에서도 8부터 제공하고 있는데,

그 덕에 인터페이스에 구현 메서드를 넣을 수 있게 되었다.

 

 

Kotlin 뉴비(ft. 올드 Java 유저...)가 신박하다 생각한, Kotlin 인터페이스 default 메서드의 두 가지 사실에 대해 알아보겠다.

 


시그니처가 동일한 default 메서드가 겹치는 경우

 

-> default 메서드를 override 해주어야 한다.

 

 

Kotlin과 Java는 다중 상속은 불가능하지만 다중 구현이 가능하다.

다중 구현이라 함은 한 클래스가 여러 인터페이스를 구현할 수 있다는 것이다.

 

 

여러 인터페이스를 구현하다보면 인터페이스 간의 메서드 시그니처가 겹칠 수도 있다.

 

 

따라서 Java에서도 충분히 발생할 수 있는 상황이다.

 

 

하지만 나는 안드로이드 개발자이고.. 최근에는 많이 사용되고는 있지만 나의 경우 Java 8과는 거리가 멀다.

그러다 보니 항상 인터페이스는 추상 메서드 밖에 없었고 동일한 메서드가 있더라도 그냥 구현하기만 하면 되었다.

 

 

하지만 default 메서드는 implements만 하면 따라오는 기본 구현인데,

컴파일러가 서로 다른 두 개 이상의 구현을 병합한다거나.. 랜덤으로 선택한다는 건 있을 수 없는 일이다..

 

 

결국 개발자가 직접 구현해 주어야 한다.

 

 

다음 코드를 보자.

 

 

class ClickImpl : Clickable, LongClickable {

}

interface Clickable {
    fun click() {
        println("click")
    }
}

interface LongClickable {
    fun click() {
        println("long click")
    }
}

 

 

이 코드를 컴파일 하면 에러가 난다.

다중 인터페이스 메서드를 상속하려하기 때문에 click 메서드를 override해라는 친절한 문구도 함께 나온다.

 

 

 

 

그렇다면 두 개의 인터페이스 구현을 모두 사용하고 싶을 땐 어떻게 하면 될까?

 

 

class ClickImpl : Clickable, LongClickable {
    override fun click() {
        super<Clickable>.click()
        super<LongClickable>.click()
    }
}

 

 

요렇게 super와 타입명을 명시하여 구현 메서드를 호출하면 된다.

 

 

Java default 메서드 알못이던 나에게는 이와 동일하게 동작하도록 하는 문법도 새로웠다.

더보기
public class ClickImpl implements Clickable, LongClickable {
    @Override
    public void walk() {
        Clickable.super.click();
        LongClickable.super.click();
    }
}    

 


Java에서 Kotlin 인터페이스 default 메서드를 사용하려는 경우

 

-> 사용하지 못한다.

 

 

Kotlin은 Java 6과 호환이 되도록 만들어졌다.

Java는 default 메서드를 Java 8부터 지원하기 시작했다.

 

 

이 말의 즉슨, Kotlin은 Java의 기능을 그대로 제공하고 있다기 보다는...

내부적인 처리를 통해 default 기능을 제공하고 있다는 말이 되겠다.

 

 

그럼 어떻게 제공을 하고 있나?

 

 

위의 Clickable 인터페이스를 bytecode decompile을 해보면 다음과 같다.

 

 

public interface Clickable {
   void click();

   public static final class DefaultImpls {
      public static void click(@NotNull Clickable $this) {
         String var1 = "click";
         boolean var2 = false;
         System.out.println(var1);
      }
   }
}

 

 

요렇게 인터페이스 안에 DefaultImpls라는 정적 클래스를 선언하고 그 안에 구현 메서드를 정적 메서드로 만들었다.

 

 

그럼 밑의 구현 클래스는 어떻게 만들어져 있을까?

 

 

class ClickImpl : Clickable

 

public final class ClickImpl implements Clickable {
   public void click() {
      Clickable.DefaultImpls.click(this);
   }
}

 

 

정적 메서드를 부르는 식으로 컴파일이 되어있다.

 

 

따라서 Java에서 Clickable을 구현하여 click 구현을 사용하는 것이 불가능해보인다.

 

 

또한 click 메서드를 새롭게 구현하지 않으면 컴파일도 되지 않는다.

 

 

Kotlin 코드의 경우 컴파일러가 알아서 default 메서드를 정적 메서드화하여 불러주는 코드를 채워주지만,

Java에서는 그것이 불가능하기 때문이다.

 

'개발 > Language' 카테고리의 다른 글

Kotlin - internal 접근제어자  (0) 2021.10.03
Java - checked/unchecked exception  (0) 2021.01.13