두 키워드를 통해 클래스 내부에 프로퍼티를 선언한 경우 멤버 필드의 가시성은 보통 private이다.
대신, 클래스는 접근자 메서드를 제공한다.
기존의 클래스명+kt라는 임의의 클래스가 생성되고 그 안에 들어가게 된다.var valTest1 = "고양이"
class Test {
var valTest2 = "강아지"
}
--------------------------------Decompile to Java-----------------------------------
//코드 생략
public final class Test {
@NotNull
private String valTest2 = "강아지";
@NotNull
public final String getValTest2() {
return this.valTest2;
}
public final void setValTest2(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.valTest2 = var1;
}
}
//코드 생략
public final class TestKt {
@NotNull
private static String valTest1 = "고양이";
@NotNull
public static final String getValTest1() {
return valTest1;
}
public static final void setValTest1(@NotNull String var0) {
Intrinsics.checkNotNullParameter(var0, "<set-?>");
valTest1 = var0;
}
}
기본적으로 가시성이 private으로 변환되는 것은 나의 생각이지만 클래스가 가진 목적 중 하나는 캡슐화이기에 직접 필드에 접근하지 못하게 한 것 같다.
둘의 차이는 간단하게 이렇게 말할 수 있다.
위 말을 이해했다면 아래 코드에서 왜 에러가 발생하는지도 쉽게 알 수 있다.
fun getKeyword():String{
return "커피"
}
class Test {
companion object{
val valTest = getKeyword()
const val constValTest = getKeyword() //ERROR
}
}
그렇다면 위 에러를 고치는 방법은 무엇일까?
그냥 const 변경자를 제거하면 된다. 그러나 여기에 ‘trade-off가 존재한다.
앞서 말했듯이 val키워드는 내부적으로 getter가 생성된다. 상수가 getter를 가진다는 것은 자연스럽지 못하다.
⇒ getter(or setter)가 생성되지 않게 하는 방법으로는 @JvmField 어노테이션이 있다.
@JvmField: Instructs the Kotlin compiler not to generate getters/setters for this property and expose it as a field.class Test {
companion object{
val valTest = getKeyword()
@JvmField
val constValTest = getKeyword()
}
}
--------------------------------Decompile to Java-----------------------------------
public final class Test {
@NotNull
private static final String valTest = TestKt.getKeyword();
@JvmField
@NotNull
public static final String constValTest = TestKt.getKeyword();\
//코드 생략
public static final class Companion {
@NotNull
public final String getValTest() {
return Test.valTest;
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
디컴파일된 코드를 보게 되면 valTest의 경우 Companion클래스 내부에 getter가 존재하는 것을 볼 수 있지만 constValTest의 경우 존재하지 않는다.
대신 constValTest의 가시성이 private에서 public으로 변경되었다. 이는 접근자메서드를 생성하지 않는 대신 필드로서 직접적으로 드러내는 것을 의미한다.
(위에 작성해놓은 JvmField의 정의 중 ’expose it as a field’ 가 그런 의미이다.)
그렇다면 우리는 @JvmField가 private을 public으로 바꿔주는 역할을 하는 것을 알 수 있다.
fun getKeyword():String{
return "커피"
}
class Test {
companion object{
@JvmField //ERROR
private val constValTest = getKeyword()
}
}
당연히 private가 붙어있는 경우 @JvmField를 사용할 수 없다.
서적: Kotlin IN ACTION