const val과 val의 차이점에 대해 알아보기
val
val x = 10 // ok
val y = listOf<String>() // ok
val z = java.util.Random().nextInt(5) // ok
val은 불변하는 값을 선언하기 위해 사용됩니다, val에는 기본 타입, String, List, 함수 등 다양한 타입을 할당할 수 있습니다.
val에 값이 할당되는 시점은 런타임 시점입니다.
만약 리스트나 함수 등을 값으로 가지고 있다면 런타임 동작에 의해 값이 변경될 수 있습니다. ex) 함수 인자 변경, list add 등등..
따라서 val은 불변한 값을 지정하기 위해 사용되지만, 재할당할 수 없을 뿐, 위 예시처럼 변경이 가능하기 때문에 불완전한 불변성을 가진다고 볼 수 있습니다.
const val
const val x = 10 // ok
const val y = listOf<String>() // error: Const 'val' has type 'List<String>'. Only primitives and String are allowed
const val z = java.util.Random().nextInt(5) // error: Const 'val' initializer should be a constant value
const val또한 불변하는 값을 선언하기 위해 사용됩니다, 하지만 const val에는 String을 포함한 기본 타입만을 할당할 수 있습니다.
그 이유는 const val에 값이 할당되는 시점이 컴파일 시점이기 때문입니다.
따라서 런타임 시점에 값이 변경될 수 있는 List, 함수등은 const val에 할당할 수 없습니다.
위 코드에서도 볼 수 있듯, 리스트 또는 함수처럼 런타임 시점의 동작에 의해 값이 변경될 수 있는 값들을 할당하려 하면 에러가 발생합니다.
따라서 const val은 완전한 불변성을 가진다고 볼 수 있습니다.
또한 const val은 파일 최상위 레벨, object, companion object와 같은 정적인 환경에서만 사용할 수 있습니다.
const val x = 10 // ok
class TestClass {
const val y = 10 // error: Const 'val' are only allowed on top level, in named objects, or in companion objects
fun testFun() {
const val z = 10 // error: Modifier 'const' is not applicable to 'local variable'
}
companion object {
const val d = 10 // ok
}
}
object TestObject {
const val g = 10 // ok
}
const val을 정적인 환경에서만 사용이 가능한것도 const val의 값 할당 시점이 컴파일 시점이기 때문입니다.
class의 내부 코드는 런타임에서 객체가 생성될 때 마다 실행되고, 함수의 내부 코드는 런타임에서 함수가 실행될 때 마다 실행되기 때문에 class와 함수는 const val을 사용할 수 없는 환경입니다.
const val을 사용하는 이유
그럼 이렇게 까다로운 const val을 왜 사용하는걸까요? 이에 대한 해답은 코드 디컴파일을 통해 알 수 있습니다.
먼저 테스트를 위해 아래와 같은 코드를 작성해 주었습니다.
object Test {
const val constValue = "const value"
val normalValue = "value"
}
fun main() {
Log.d("logtag", Test.constValue)
Log.d("logtag", Test.normalValue)
}
작성 후 이 코드를 디컴파일해 자바코드로 확인해보면
// main 함수 디컴파일 코드
public final class MainKt {
public static final void main() {
Log.d("logtag", "const value");
Log.d("logtag", Test.INSTANCE.getNormalValue());
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
위와 같은 코드를 확인할 수 있습니다.
코드에서도 알 수 있듯 일반 val에 접근하면 객체를 생성해 해당 값에 대한 getter를 사용하여 접근하지만, const val을 사용하는 값은 컴파일 시점에 사용위치에 해당 값이 그대로 들어가게 됩니다.
이처럼 const val을 사용하면 런타임 시점에서의 오버헤드를 줄일 수 있습니다.
* 오버헤드(overhead): 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말함
마무리
요약
- val은 런타임 시점에 값 할당, const val은 컴파일 시점에 값을 할당한다.
- val은 불완전한 불변성을, const val은 완전한 불변성을 가진다.
- val은 모든 타입을, const val은 String을 포함한 기본 타입만을 가질 수 있다.
- const val을 쓸 수 있는 상황에는 사용하는것이 약간의 오버헤드를 줄일 수 있다.
오늘은 Kotlin의 const val과 val의 차이점에 대해 알아보았습니다. 보충해야할 부분이나 잘못된 부분이 있다면 댓글로 지적 부탁드립니다, 글 읽어주셔서 감사합니다!
'Kotlin' 카테고리의 다른 글
[Kotlin] Kotlin in Action 1. 함수와 변수 (0) | 2024.11.19 |
---|