변수

맥모닝·2023년 11월 8일
0

Kotlin

목록 보기
3/10

변수

val(value의 약자)

💡 초기화 이후 변수의 값을 변경할 수 없지만, val이 가리키는 객체의 내부 값은 변경될 수 있다.

  • 변경 불가능한 참조를 저장하는 변수다.
    • 초기화 이후 변수의 값을 변경할 수 없다.
  • 컴파일러가 문맥을 살펴봤을 때 오직 한번만 초기화 되는 것이 맞다면 조건에 따라 val 값을 여러 값으로 초기화할 수 있다.
  • 변경이 불가능하지만 val이 가리키는 객체의 내부 값은 변경될 수 있다.

var(variable의 약자)

💡 초기화 이후 변수의 값을 변경할 수 있고, 초기화한 타입으로만 변경이 가능하다.

  • 변경 가능한 참조를 저장하는 변수다.

const

💡 값이 컴파일 시에 결정되는 상수로서, String을 포함한 원시 타입으로만 선언이 가능하다.

  • 읽기 전용 변수인 val 앞에 const 키워드를 붙여서 만든다.
  • 상수(static final(feat. Java)). 초기화 이후 내부의 값을 사용할 수 있지만, 바꿀 수는 없다.
    • val과 같은 특성이지만 불변성의 차이가 존재한다.
  • val과 읽기 전용인 것은 동일하지만 컴파일 시 값이 결정되기 때문에 String을 포함한 원시 타입으로만 선언이 가능하다.
    • val은 함수 및 객체 등 여러가지 타입으로 초기화 가능하다.

val과 const val의 상수 차이

val

  • 불완전한 불변성 : 값이 런타임 시에 결정되는 상수
    • 독립적인 프로그램 수행 중에 프로그램 수행에 따라 값이 바뀔 수 있다.

const val

  • 불변성 : 값이 컴파일 시에 결정되는 상수
  • 클래스의 생성자에 할당될 수 없으며, String을 포함한 원시 타입으로만 선언이 가능하다.
  • 함수 내의 지역 변수나, 클래스의 속성으로 사용할 수 없다.
    • 따라서 함수나 클래스 내에서 사용하려면 companion object 안에 선언해야한다.
  • 클래스의 상태와 관계없이 언제나 동일한 값을 가진다.
  • 이름을 결정할 때에는 일반적인 변수와 달리 대문자와 _사용한다.
  • 컴파일 시에 데이터가 메모리에 존재하기 때문에, 사용 시 객체 생성해서 이에 접근하는 것이 아니라 클래스명.상수명의 형태를 사용해서 직접 접근한다.
  • 클래스의 객체를 생성한 뒤 사용해야 하는 클래스의 속성의 소요시간을 줄임으로 성능이 향상된다.

컴파일 시점 vs 런타임 시점

💡 런타임 시점에 값을 할당하면 상수에 접근하여 확인하지만, 컴파일 시점에 값을 할당하면 컴파일러는 해당 상수가 가지고 있는 값을 미리 알 수 있다는 장점이 있다.

런타임 시점

컴파일된 프로그램이 실제로 실행되고 동작하는 시간을 의미한다. 프로그램이 실행 중일 때 발생하는 시간 동안 작업을 수행하고 데이터를 처리하며, 사용자와의 상호작용이 이루어진다.

// val 키워드를 통해 상수를 선언
object Constants {
    val NAME = "BuNa"
}

// Kotlin
fun testValWithoutConst() {
    val name = Constants.NAME
}
// Decompiled Java
public final void testValWithoutConst(){
    String name = Constants.INSTANCE.getNAME();
}
  • Kotlin을 Java로 디컴파일한 결과, "BuNa"라는 값을 가지고 있는 NAME 상수에 접근하는 모습을 확인할 수 있다.

컴파일 시점

컴파일러를 통해 개발자가 작성한 소스 코드를 시스템이 이해할 수 있는 기계어로 번역하는 데 발생하는 시간으로, 소스 코드를 수정하거나 추가할 때 오류를 미리 발견하여 안전성을 높이는 역할을 한다.

// val 키워드를 통해 상수를 선언
object Constants {
    const val NAME = "BuNa"
}

// Kotlin
fun testVal WithoutConst() {
    val name = Constants.NAME
}
  • Kotlin을 Java로 디컴파일한 결과, 참조하는 쪽에서 NAME 상수에 직접 접근하지 않고, "BuNa"라는 literal string을 직접 가지고 있음을 확인할 수 있다.
  • 컴파일러는 컴파일 시점에 이미 NAME 상수가 어떤 값을 가지고 있는지 알 수 있기 때문에, 값으로 대체가 가능하다.
// Decompiled Java
public final void testValWithoutConst(){
    String name = "BuNa"
}
  • NAME이 "BuNa"로 인라인 되면서, 값을 참조할 때마다 상수에 접근하면서 발생하는 오버헤드를 줄일 수 있다.

참고한 사이트

profile
필요한 내용을 공부하고 저장합니다.

0개의 댓글