안녕하세요 케니스입니다 👋
이번에는 kotlin.jvm 패키지에 있는 코틀린 코드를 자바에서 활용할 때 유용하고 자주 사용되는 어노테이션에 대해서 알아보겠습니다.
@JvmName
은 Java의 클래스 또는 메소드의 이름을 지정합니다.
보통 @JvmName
은 Kotlin 메서드 또는 클래스를 JVM 바이트코드로 변환 하고 Java에서 호출되는 Kotlin 함수나 클래스의 이름이 동일한 시그니처일 때 이를 처리하기 위해서 사용합니다.
아래코드는 같은 이름을 가진 함수의 다형성 예시입니다.
fun foo(names: List<String>): List<String>
fun foo(numbers: List<Int): List<Int>
위 코드를 컴파일 하면 아래와 같은 에러를 발생하게 됩니다.
Error:(7, 1) Kotlin: Platform declaration clash: The following declarations have the same JVM signature (foo(Ljava/util/List;)V):
fun foo(a: List<Int>): Unit defined in foo.main.kotlin in file kotlin.kt
fun foo(a: List<String>): Unit defined in foo.main.kotlin in file kotlin.kt
이유는 바이트코드 생성시 List의 Generic 값은 구분되지 않기 때문에 두개가 동일한 메서드로 판단되기 때문이다. 이럴 때 @JvmName
어노테이션을 사용하여 이름을 지정해주면 해결된다.
@JvmName(name = "names")
fun foo(names: List<String>): List<String>
@JvmName(name = "numbers")
fun foo(numbers: List<Int): List<Int>
Kotlin 컴파일러에게 @JvmField
어노테이션을 선언한 프로퍼티에 대해 getters/setters를 생성하지 않게 요청합니다.
@JvmField
어노테이션 사용 제약은 다음과 같습니다.
private
는 불가open
override
const
키워드가 아닌 경우delegate
프로퍼티가 아닌 경우 class Store(
val name: String,
@JvmField val latitude: Long
)
Java에서 다음과 같이 사용할 수 있습니다.
public void main() {
Store store = new Store("Cafe", 128.1234567)
String name = store.getName();
long latitude = store.latitude;
}
함수 또는 프로퍼티에 static으로 접근 가능한 getter / setter 를 생성합니다.
object Log {
fun d(log: String) {
println("d: $log")
}
@JvmStatic
fun e(log: String) {
println("e: $log")
}
}
위의 코드의 @JvmStatic
선언되어 있지 않은 d 함수를 호출할 때 kotlin, java에서 각 아래와 같이 호출됩니다.
// Java
public void main() {
Log.INSTANCE.d("log")
}
// Kotlin
fun main() {
Log.d("log")
}
Java 에서 Kotlin 함수 또느 프로퍼티를 static하게 사용하려면 @JvmStatic
어노테이션을 사용하면 됩니다.
@JvmStatic
선언된 Log object 클래스의 e 함수를 실행하면 다음과 같이 사용할 수 있습니다.
// Java
public void main() {
Log.e("log")
}
kotlin
클래스의 오버로딩 메소드들을 생성해주는 어노테이션입니다.
kotlin
클래스는 생성자에 기본인자를 정의하고 인스턴스를 생성할 때 다음과 같이 사용할 수 있습니다.
class User constructor(
val id : Int = 0,
val name: String = "Kenneth"
)
fun main() {
User(id = 0)
User(name = "Kenneth")
User(id = 0, name = "Kenneth")
}
Java에서는 기본인자를 제공하지 않기 때문에 kotlin
으로 작성된 User
클래스의 인스턴스를 생성시 모든 파라미터를 작성해주어야 하는 불편함이 있습니다.
public void main() {
new User(0) // compile error
new User(0, "Kenneth")
}
이 때 @JvmOverloads
어노테이션을 추가하면 kotlin compiler
가 자동으로 다양한 생성자 오버로드 함수들을 만들어 줍니다.
class User @JvmOverloads constructor(
val id : Int = 0,
val name: String = "Kenneth"
)
@JvmOverload
적용 후에는 Java에서 id의 값만 가지는 User
인스턴스도 생성이 가능해집니다.
public void main() {
new User(0)
new User(0, "Kenneth")
}
@Throws
는 컴파일 타임에 코틀린 함수가 예외를 던질 수 있다는 것을 의미하는 어노테이션입니다.
Java
에서 throws
와 같은 키워드는 Kotiln
에 없기 때문에 @Throws
를 사용합니다
@Throws(RuntimeException::class)
fun execute()
명확한 사용의도를 알지 못하고 사용했을 때 이해가 안가는 부분도 많았지만
이렇게 살펴보니 어떤 목적을 위해 바르게 써야하는지 익힐 수 있는 경험이 었습니다
다들 즐거운 코딩하세요 🤗