본문 바로가기

Kotlin

[Kotlin] Kotlin 기본 문법 by "Code with Joyce" 2편 - (2)

Code with Joyce님과 함께하는 '코틀린 3강으로 끝내기 - 2편 기본 문법'이다.

 

1. Companion Object

가장 이해하기 난해했던 내용으로 사실상 '암기'하기로 결정 내린 부분이다.

 

Joyce님이 Companion Object를 설명할 때 클래스의 static 멤버(member)로 소개했으며 효과 또한 static 멤버와 동일해 보였기 때문에 'Companion Object는 static 멤버이다'라고 이해했다. 그러나 다른 사람들의 의견과 Kotlin 공식문서를 통해서 Companion Object는 static 멤버와 유사할 뿐이지 실제 객체의 인스턴스 멤버라고 암기했다.

 

각설하고, 클래스의 인스턴스(instance)와 독립적으로 사용될 클래스 멤버를 정의하기 위해 Companion Object를 사용해야 하는 경우가 있다. 여타 다른 언어에서 보이는 static과 유사해 보이는 이것은 인스턴스가 1개뿐임을 보장하기 때문이다.

 

Companion Object를 선언하는 방법은 아래와 같다.

 

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

 

Companion Object에 'Factory'라고 명명되어 있지만 생략해도 무방하다. 이름을 생략해서 사용할 경우, 컴파일러가 자동으로 'Companion'이라는 이름을 붙여준다.

 

이후 인스턴스를 생성해서 Companion Object의 멤버를 참조할 수 있다. 아래는 인스턴스의 생성 방법이다.

 

val instance = MyClass.Factory.create()

// Factory 생략 가능
val instance = MyClass.create()

// Companion Object 선언에 이름이 생략된 경우
val instance = MyClass.Companion

// Companion 조차 생략 가능
val instance = MyClass

 

Companion Object는 속성과 메서드를 멤버로 가질 수 있다. 해당 멤버들은 앞서 설명했듯이 생성된 인스턴스를 통해서 참조할 수 있고, 클래스의 이름을 통해서도 참조할 수 있다.

 

class MyClass {
    companion object Factory {
        val prop = "나는 Companion object의 속성이다."
        fun method() = "나는 Companion object의 메서드다."
        fun create(): MyClass = MyClass()
    }
}

fun main() {
    
    // 인스턴스로 Companion Object 멤버 참조
    val instance = MyClass.create()
    
    println(instance.prop)
    println(instance.method())
    
    // 클래스 이름으로 Companion Object 멤버 참조
    println(MyClass.Factory.prop)
    println(MyClass.method())
}

/*
result

    나는 Companion object의 속성이다.
    나는 Companion object의 메서드다.
    나는 Companion object의 속성이다.
    나는 Companion object의 메서드다.
*/

 

2. Companion Object는 static 멤버가 아니다.

Kotlin 공식 문서에서 확인한 내용으로 Companion Object는 static 멤버가 아니라고 한다.

 

Note that even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces

 

위의 내용이 공식 문서의 내용이며 해석하면 아래와 같다.

 

Companion Object의 멤버가 다른 언어에서는 static 멤버처럼 보이지만 런타임에는 여전히 실제 객체의 instance 멤버이며 그러므로 interface를 구현할 수 있습니다.

 

실제로 Java에서는 static class가 interface를 구현하려고 하면 오류가 발생한다.

 

interface Factory {
    void work();
}

// syntex error : Modifier 'static' not allowed here
static class worker implements Factory {
    public void work() {
        System.out.println();
    }
}

 

반대로 Kotlin은 interface를 구현할 수 있다.

 

interface Factory<T> {
    fun create(): T
}

class MyClass {
    companion object : Factory<MyClass> {
        override fun create(): MyClass = MyClass()
    }
}

val f: Factory<MyClass> = MyClass

 

공식 문서가 말하기를, 만약 실제로 static 멤버로 Comapnion Object를 활용하고 싶다면 어노테이션 @JvmStatic을 사용하면 된다고 한다. 해당 어노테이션을 사용하면 JVM에서 실제 정적 메서드 및 필드로 생성된 Companion Object의 구성원을 가질 수 있다.

 

3. 참고

 

[kotlin] Companion Object (1) - 자바의 static과 같은 것인가? - Bsidesoft co.

개요 코틀린(Kotlin)의 Companion object는 단순히 자바(Java)의 static 키워드를 대체하기 위해서 탄생했을까요? 이 갑작스러운 질문은 코틀린에서 왜 static을 안 쓰게 되었는지 이해하는 데 큰 도움이 될

www.bsidesoft.com

https://kotlinlang.org/docs/object-declarations.html