logo

Tech

후기

회고

Study

Java
Kotlin

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

avatar

초코칩

2025년 04월 04일 17:20

공유하기
클립보드로 복사
thumbnail

코틀린에서 변수를 선언하는 키워드인 valvar에 대해 알아봅니다. 이 두 키워드는 코틀린의 핵심 철학인 간결함과 안전성을 잘 보여주는 요소입니다.

이번 글에서는 이들의 기본 차이점을 시작으로, 클래스 내에서의 동작과 바이트 코드 수준에서의 차이까지 살펴봅니다.

val과 var

varval은 변수를 선언할 때 사용하는 키워드입니다. 둘의 가장 큰 차이점은 변경 가능성(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에 대한 이해도가 높다면, valvar의 차이를 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
}

위 코드에서 확인해야 할 부분은 세 곳입니다.

  1. final
private final java.lang.String immutable;

val immutableprivate final 필드로 컴파일됩니다. final 키워드는 이 필드가 불변임을 나타내어 생성자에서 값을 설정한 뒤에는 재할당이 불가능하게 합니다. 반면 var mutablefinal 없이 private java.lang.String mutable로 선언되어 값 변경이 가능합니다.

  1. 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

valvar 모두 Getter가 생성됩니다. getImmutable()getMutable()은 각각 필드 값을 반환하는 역할을 합니다. 코틀린에서는 프로퍼티 접근(car.immutable, car.mutable)이 바이트 코드에서 getter 호출로 변환됩니다.

  1. Setter 생성 여부
public final void setMutable(java.lang.String);
    Code:
       0: aload_1
        ...
      11: return

var mutable은 Setter(setMutable)가 생성되어 값을 변경할 수 있습니다. 반면 val immutable은 Setter가 없기 때문에 값을 바꾸려 하면 컴파일 오류가 발생합니다. 이는 val의 불변성을 JVM 수준에서 보장하는 핵심적인 차이입니다.

이 바이트 코드를 통해 valfinal로 불변성을 강제하고 Setter가 생략되며, var은 Setter를 포함해 가변성을 지원한다는 점을 명확히 알 수 있습니다. 이런 차이는 코틀린이 소스 코드 수준에서 제공하는 안전성과 간결함이 JVM 바이트 코드로 어떻게 변환되는지를 보여줍니다.

Ref