var과 val의 차이점은 무엇일까?

초코칩
2025년 04월 04일 17:20

코틀린에서 변수를 선언하는 키워드인 val
과 var
에 대해 알아봅니다. 이 두 키워드는 코틀린의 핵심 철학인 간결함과 안전성을 잘 보여주는 요소입니다.
이번 글에서는 이들의 기본 차이점을 시작으로, 클래스 내에서의 동작과 바이트 코드 수준에서의 차이까지 살펴봅니다.
val과 var
var
와 val
은 변수를 선언할 때 사용하는 키워드입니다. 둘의 가장 큰 차이점은 변경 가능성(mutability)에 있습니다.
val
val
(Value)은 불변 변수를 선언합니다. 한 번 값이 할당되면 재할당할 수 없습니다. 자바의 final
변수와 비슷한 개념입니다.
val x: Int = 5
x += 5 // Val cannot be reassigned error
var
var
(Variable)는 가변 변수를 선언합니다. 필요에 따라 값을 여러 번 변경할 수 있습니다.
var x: Int = 5
// Reassigns a new value of 6 to the variable x
x += 1 // 6
바이트 코드로 살펴보기
Java에 대한 이해도가 높다면, val
과 var
의 차이를 JVM 바이트 코드 수준에서 더 깊이 확인할 수 있습니다.
다음 Car 클래스에 대한 바이트 코드를 살펴봅니다.
class Car {
val immutable = "Immutable"
var mutable = "Mutable"
}
바이트 코드는 아래와 같습니다.
Compiled from "Car.kt"
public final class Car {
private final java.lang.String immutable;
private java.lang.String mutable;
public Car();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #10 // String Immutable
7: putfield #14 // Field immutable:Ljava/lang/String;
10: aload_0
11: ldc #16 // String Mutable
13: putfield #19 // Field mutable:Ljava/lang/String;
16: return
public final java.lang.String getImmutable();
Code:
0: aload_0
1: getfield #14 // Field immutable:Ljava/lang/String;
4: areturn
public final java.lang.String getMutable();
Code:
0: aload_0
...
4: areturn
public final void setMutable(java.lang.String);
Code:
0: aload_1
...
11: return
}
위 코드에서 확인해야 할 부분은 세 곳입니다.
- final
private final java.lang.String immutable;
val immutable
은 private final
필드로 컴파일됩니다. final
키워드는 이 필드가 불변임을 나타내어 생성자에서 값을 설정한 뒤에는 재할당이 불가능하게 합니다.
반면 var mutable
은 final
없이 private java.lang.String mutable
로 선언되어 값 변경이 가능합니다.
- Getter 생성 여부
public final java.lang.String getImmutable();
Code:
0: aload_0
1: getfield #14 // Field immutable:Ljava/lang/String;
4: areturn
public final java.lang.String getMutable();
Code:
0: aload_0
...
4: areturn
val
과 var
모두 Getter가 생성됩니다. getImmutable()
과 getMutable()
은 각각 필드 값을 반환하는 역할을 합니다.
코틀린에서는 프로퍼티 접근(car.immutable
, car.mutable
)이 바이트 코드에서 getter 호출로 변환됩니다.
- Setter 생성 여부
public final void setMutable(java.lang.String);
Code:
0: aload_1
...
11: return
var mutable
은 Setter(setMutable
)가 생성되어 값을 변경할 수 있습니다. 반면 val immutable
은 Setter가 없기 때문에 값을 바꾸려 하면 컴파일 오류가 발생합니다.
이는 val
의 불변성을 JVM 수준에서 보장하는 핵심적인 차이입니다.
이 바이트 코드를 통해 val
은 final
로 불변성을 강제하고 Setter가 생략되며, var
은 Setter를 포함해 가변성을 지원한다는 점을 명확히 알 수 있습니다.
이런 차이는 코틀린이 소스 코드 수준에서 제공하는 안전성과 간결함이 JVM 바이트 코드로 어떻게 변환되는지를 보여줍니다.