Kotlin/Class and Interface

Kotlin object의 초기화 시점과 companion object의 초기화 시점 차이 알아보기

object와 companion object의 초기화 시점

object는 싱글톤 인스턴스를 간편하게 만들기 위해 Kotlin에서 제공해주는 방법이다. object를 작성하면 싱글톤 패턴을 구현하기 위한 긴 코드를 작성할 필요 없이 쉽게 싱글턴 객체를 만들 수 있다. companion object 또한 클래스에 종속된 정적인(static) 값들을 만드는데 사용되며 여러번 생성되는 것이 아닌 한 번만 생성되는 싱글턴 패턴을 가진다.

 

하지만 Kotlin에서 object와 companion object는 서로 다른 초기화 시점을 갖는다. 이번 글에서는 각각의 초기화 시점에 대해 알아보려고 한다.

 

object의 초기화 시점

object는 실제로 사용 될 때까지 초기화가 지연된다. 이에 대한 것은 공식 문서에 다음과 같이 나와있다.

 

The initialization of an object declaration is thread-safe and done on first access.

 

*참조: Object declarations

 

Object expressions and declarations | Kotlin

 

kotlinlang.org

 

이를 번역하면 object의 초기화는 스레드 안전하며, 최초 접근 시점에 수행된다는 뜻이고, 다른 말로하면 object가 처음 사용될 때까지 초기화가 지연된다는 뜻이다.

 

실제로 그런지 알아보기 위해서는 다음 코드를 수행하면 된다.

object DevWorld {
    init {
        println("Hello Dev World")
    }
}

fun main() {
    println("Before accessing DevWorld.")
    DevWorld
    println("After accessing DevWorld.")
}

 

위 코드를 실행하면 다음 결과가 나온다. 

Before accessing DevWorld.
Hello Dev World
After accessing DevWorld.

 

object에 처음 접근하는 시점에 init 블록이 불려서 DevWorld is being initialized가 출력되어 초기화 되는 것을 확인할 수 있다.

 

 

companion object의 초기화 시점

반면 companion object는 클래스의 인스턴스가 로드될 때 즉시 초기화 된다. companion object의 초기화 시점은 Kotlin 공식 문서에 다음과 같이 나와있다.

 

 

A companion object is initialized when the corresponding class is loaded (resolved) that matches the semantics of a Java static initializer.

 

*참조: Semantic difference between object expressions and declarations

 

Object expressions and declarations | Kotlin

 

kotlinlang.org

 

위 글을 요약하면 companion object의 초기화 시점은 클래스가 로딩되는 시점은 클래스가 처음 로딩되는 시점이라는 뜻이다. JVM에서는 먼저 클래스의 메타 데이터만 Method Area에 저장하고 클래스를 사용할 때 클래스를 실제로 로드한다. 이때가 바로 class에 종속된 companion object의 로딩 시점이다. 이는 Java의 static한 값도 마찬가지므로, companion object는 Java의 static한 변수, 함수와 동일한 시점에 초기화 된다고 할 수 있다.

 

*만약 클래스 로더에 대해 잘 모른다면 아래 글을 참고하도록 하자.

 

[메모리] JVM의 메모리 사용 방식 : JVM의 Static Area와 Heap Area를 중심으로 Kotlin/JVM의 메모리 사용방

목표 각 Memory Area가 어떤 역할을 하는지 이해한다. JVM의 메모리 구조 JVM은 Runtime에 Data를 올려놓는 공간인 Runtime Data Area를 가지고 있다. 이 공간은 총 5가지로 나뉘는데, 뒤의 PC Register과 Native Metho

kotlinworld.com

 

이를 확인하기 위해 아래 코드를 수행해보자. 아래 코드에서 companion object는 초기화 시 호출되는 init 블록에서 println("DevWorld.Companion is being initialized.")를 명령을 수행한다.

class DevWorld {
    companion object {
        init {
            println("DevWorld.Companion is being initialized.")
        }
    }
}

fun main() {
    println("Before accessing DevWorld.")
    DevWorld
    println("After accessing DevWorld.")
}

 

위 코드를 실행하면 다음과 같은 결과를 얻을 수 있다.

Before accessing DevWorld.
DevWorld.Companion is being initialized.
After accessing DevWorld.

 

이 출력 결과에서 확인할 수 있듯이 companion object는 클래스에 처음 접근하는 시점에 즉시 초기화된다. DevWorld에 처음 접근하는 부분에서 companion object의 초기화가 수행되고, "DevWorld.Companion is being initialized" 가 출력 되는 것을 확인할 수 있다. 

반응형

 

이 글의 저작권은 '조세영의 Kotlin World' 에 있습니다. 글, 이미지 무단 재배포 및 변경을 금지합니다.

 

 

Kotlin, Android, Spring 사용자 오픈 카톡

오셔서 궁금한 점을 질문해보세요!
비밀번호 : kotlin22

open.kakao.com