발표 동기

회사에 던진 의문점

이 글을 적게 된 계기

박사 학위가 생겨서 좋네요

Kotlin interface in JVM

Kotlin의 interface는 아래와 같이 메서드를 구현을 할 수 있습니다.

interface 인터페이스 {
    fun 기본매서드() {
        println("기본메서드 실행!!")
    }
}

Java에서는 Java 1.8 이후부터 default 키워드를 제공하여 interface에 default method를 사용할 수 있습니다.

public interface 인터페이스 {
    default void 기본매서드() {
        System.out.println("기본메서드 실행!!")
    }
}

그러면 위 Kotlin 코드를 Bytecode로 반환하면 어떻게 표현될까요?

// ================siwony/kotlin14/인터페이스.class =================
// class version 61.0 (61)
// access flags 0x601
public abstract interface siwony/kotlin14/인터페이스 {

// compiled from: 인터페이스.kt

@Lkotlin/Metadata;(mv={1, 9, 0}, k=1, xi=48, d1={"\u0000\u0010\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u0002\n\u0000\u0008f\u0018\u0019
// access flags 0x19
public final static INNERCLASS siwony/kotlin14/인터페이스$DefaultImpls siwony/kotlin14/인터페이스 DefaultImpls

// access flags 0x401
public abstract 기본매서드()V
}


// ================siwony/kotlin14/인터페이스$DefaultImpls.class ===============
// class version 61.0 (61)
// access flags 0x31
public final class siwony/kotlin14/인터페이스$DefaultImpls {

// compiled from: 인터페이스.kt

@Lkotlin/Metadata;(mv={1, 9, 0}, k=3, xi=48)
// access flags 0x19
public final static INNERCLASS siwony/kotlin14/인터페이스$DefaultImpls siwony/kotlin14/인터페이스 DefaultImpls

// access flags 0x9
public static 기본매서드(Lsiwony/kotlin14/인터페이스;)V
// annotable parameter count: 1 (invisible)
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
LINENUMBER 5 L0
LDC "\uae30\ubcf8\uba54\uc11c\ub4dc \uc2e4\ud589!!"
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
SWAP
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L1
LINENUMBER 6 L1
RETURN
L2
LOCALVARIABLE $this Lsiwony/kotlin14/인터페이스; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
}

이를 Java 코드로 Decompile 해보면 인터페이스에 static inner class가 선언되어 있습니다. 안에는 kotlin코드에서 작성한 기본 메서드가 선언되어 있네요.

@Metadata(
    mv = {1, 9, 0},
    k = 1,
    xi = 48,
    d1 = {"\u0000\u0010\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u0002\n\u0000\bf\u0018\u00002\u00020\u0001J\b\u0010\u0002\u001a\u0"},
    d2 = {"Lsiwony/kotlin14/인터페이스;", "", "기본매서드", "", "kotlin14"}
)
public interface 인터페이스 {
    void 기본매서드();

    @Metadata(
        mv = {1, 9, 0},
        k = 3,
        xi = 48
    )
    public static final class DefaultImpls {
        public static void 기본매서드(@NotNull 인터페이스 $this) {
            String var1 = "기본메서드 실행!!";
            System.out.println(var1);
        }
    }
}

Kotlin 1.2

kotlin1.2 부터 Java 8를 대상으로 @JvmDefault를 이용해 default method를 지원하기 시작했습니다. 다만 -Xjvm-default 컴파일 옵션에서만 작동합니다.

interface Alien {
    @JvmDefault
    fun speak() = "Wubba lubba dub dub"
}

class BirdPerson : Alien

하지만 kotlin1.4 @JvmDefault는 Deprecated 되었습니다.

Kotlin 1.4 ~ 현재

인터페이스에서 기본 메서드를 생성하기 위한 새로운 모드 2개

-Xjvm-default=all

  • default method만 존재하고, DefaultImpls 객체가 더 이상 없음

-Xjvm-default=all-compatibility

  • binary compatibility(이진 호환성)을 보장하는 모드
  • default method와 DefaultImpls 둘 다 생기지만 DefaultImpls method는 정의된 default method를 호출하도록 함

더 찾아보면 좋은 문서들

Reference