코틀린 파일의 최상위에 선언된 함수가 컴파일 될 때 일어나는 일
코틀린에서는 .kt 파일을 만든 다음 최상위에 함수를 선언하는 것이 허용된다. 예를 들어 다음과 같이 main 패키지 안에 선언된 Main.kt파일 내부에 printHello 함수가 선언되어 있다고 해보자.
우리가 이를 바이트 코드로 컴파일 하면 다음과 같이 MainKt.class 파일이 생성되며, 이 MainKt 클래스 내부에는 printHello 함수가 정적 함수로 선언된다.
따라서 우리는 이 함수를 자바 파일에서 다음과 같이 사용할 수 있다.
import main.MainKt;
public class Test {
public static void main(String[] args) {
MainKt.printHello();
}
}
위 코드가 IDE에 작성된 모양은 [그림3] 과 같다.
위와 같은 방법의 문제와 @JvmName 어노테이션을 사용한 해결
위와 같은 상황은 일반적으로 아무런 문제가 되지 않지만, 가끔 하나의 파일 내부에 수많은 최상위 함수가 선언돼 있는 경우가 있다. 이런 경우 사람들은 최상위 함수를 용도 별로 파일로 분류하고, 최상위 함수를 포함하는 파일의(클래스)의 명칭을 바꾸고 싶어한다. 여기서 @JvmName 어노테이션이 등장한다.
최상위 함수가 컴파일 되면서 정적 함수로 변환되며 포함되는 클래스의 이름은 [파일명]Kt이다(위에서는 Main.kt파일이 MainKt로 변경되었다). 하지만 @JvmName 어노테이션이 적용된 파일명은 이 클래스의 이름을 바꾼다. 예를 들어 위의 Main.kt 파일을 다음과 같이 바꿔보자.
@file: JvmName("Printer")
package main
fun printHello() {
println("Hello")
}
fun printBye() {
println("Bye")
}
다시 빌드를 해보면 MainKt.class 대신 Printer.class가 생성된 것을 확인할 수 있다.
그러면 이제 이 클래스는 자바 파일에서 다음과 같이 사용이 가능해진다.
import main.Printer;
public class Test {
public static void main(String[] args) {
Printer.printHello();
Printer.printBye();
}
}
*물론 이러한 최상위 함수를 리펙토링하는 가장 좋은 방법은 최상위 함수를 클래스에 포함시킨 후, 해당 함수가 필요한 객체에 클래스의 인스턴스를 주입시키는 방식이다. 이렇게 하면 클래스를 주입할 수 있게 돼 테스트 더블을 만들기가 쉬워지고, 유지 보수가 좋아진다. 하지만, 최상위 함수로 선언된 함수를 수없이 많은 곳에서 사용되는 경우가 많기 때문에, 이렇게 클래스로 나누기 위에 너무 많은 변경이 필요한 경우가 있다.
반응형