출처
https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces
https://blog.jetbrains.com/kotlin/2020/07/kotlin-1-4-m3-generating-default-methods-in-interfaces/
코틀린은 인터페이스에 default method를 선언할 수 있지만, 자바는 1.8부터 인터페이스 안에 default method를 기입할 수 있게 되었다.
1. 다른 설정없이 코드 변환
interface Fruit {
fun color() : String
fun bloom() = println("blooming")
}
-> 자바로 컴파일
public interface Fruit {
@NotNull
String color();
void bloom();
@Metadata(
mv = {1, 7, 0},
k = 3
)
public static final class DefaultImpls {
public static void bloom(@NotNull Fruit $this) {
String var1 = "blooming";
System.out.println(var1);
}
}
}
DefaultImpls 클래스를 내부 클래스로 생성한다.
😮 자바도 interface 안에 default method를 선언할 수 있는데, 코틀린으로 변환하면 왜 구지 내부 클래스로 생성할까?
자바 구버전과의 호환성 때문에. 자바 Java 8 미만 버전에서는 interface 안에 default method를 생성할 수 없었다.
2. @JvmDefault 이용
@JvmDefault는 Kotlin 1.2에서 실험적으로 등장해 코틀린의 인터페이스의 default method를 자바의 인터페이스 default method로 변환한다. Java 8을 타겟으로 한다. @JvmDefault는 Deprecated 됐다.
interface Fruit {
fun color() : String
@JvmDefault
fun bloom() = println("blooming")
}
-> 자바로 변환
public interface Fruit {
@NotNull
String color();
@JvmDefault
default void bloom() {
String var1 = "blooming";
System.out.println(var1);
}
}
@JvmDefault는 인터페이스의 default method에 일일이 붙여줘야하는 수고로움이 있고, 위임의 경우에 오버라이드된 디폴트 메소드가 호출되지 않는 이슈가 있다.
위임 이슈 확인
interface Fruit {
fun color() : String
@JvmDefault
fun bloom() = println("blooming")
}
class Orange : Fruit {
override fun color() = "orange"
override fun bloom() = println("end blooming")
}
class Apple(fruit: Fruit): Fruit by fruit
fun main() {
val orange = Orange()
val apple = Apple(orange)
apple.bloom()
// 결과로 "end blooming"의 출력을 예상하지만, 실제로는 "blooming"이 출력된다.
}
3. -Xjvm-default=all 또는 -Xjvm-default=all-compatibility 사용
컴파일 옵션 설정 - IntelliJ
코틀린 코드
interface Fruit {
fun color() : String
fun bloom() = println("blooming")
}
class Orange : Fruit {
override fun color() = "orange"
override fun bloom() = println("end blooming")
}
class Apple(fruit: Fruit): Fruit by fruit
fun main() {
val orange = Orange()
val apple = Apple(orange)
apple.bloom() // "end blooming"으로 출력됨
}
-> 자바 변환 코드
public interface Fruit {
@NotNull
String color();
default void bloom() {
String var1 = "blooming";
System.out.println(var1);
}
}
옵션 설명
- -Xjvm-default=all : 더이상의 DefaultImpls 객체없이 default methods만 있을 경우
- -Xjvm-default=all-compatibility : -Xjvm-default를 사용하는 새 스키마로 컴파일된 클래스가 이전 스키마(DefaultImpls 포함)로 컴파일된 인터페이스를 구현하는 경우
위의 코드를 보면, DefaultItmpls를 통해 default method를 호출한다.
그래서 이렇게 사용해도 되기 때문에, 과거 스키마를 가진 코드와 호환이 된다.
😮 -Xjvm-default=all-compatibility를 사용하는 경우 바이너리 호환성이 원활하지 않아 컴파일 에러가 생기는 이슈가 생길 수 있다. 이 경우에는 @JvmDefaultWithoutCompatibility를 사용해서 특정 클래스만 DefaultImpls 없이 자바 인터페이스 default method를 사용하게 할 수 있다.
'빈 구멍 채우기' 카테고리의 다른 글
[Kotlin] init 블록 (3) | 2024.11.04 |
---|---|
[JVM] invokedynamic 이해하기 (0) | 2024.11.01 |
[Kotlin] const val (0) | 2024.10.29 |
[Kotlin] @JvmOverloads - 디폴트 파라미터를 자바에서도 이용하기 (0) | 2024.10.29 |
[Kotlin] @JvmField : 컴파일시 게터, 세터 없애기 (1) | 2024.10.29 |