Programming/Kotlin

코틀린(Kotlin) - 오브젝트(object): 객체 선언, 동반 객체, 객체 식

JunsuKim 2021. 10. 10.
728x90

객체 선언: 싱글톤

객체 선언은 클래스 선언과, 클래스에 속한 단일 인스턴스의 생성, 변수에 인스턴스 저장을 동시에 처리해주기 때문에 싱글톤에 사용하기 적합하다.

object Payroll {
    val allEmployees = arraylistOf<Person>()
    
    fun calculateSalary() {
        for(person in allEmployees) {
            . . . .
        }
    }
}

payroll.allEmployees.add(Person(. . . .))
payroll.calculateSalary()

싱글톤은 객체 선언 키워드인 object로 시작하면 된다.

객체 선언

객체 선언의 특징은 다음과 같다.

  • 프로퍼티, 메서드, 초기화 블록이 가능하다.
  • 생성자는 객체 선언에 사용할 수 없다.(주 생성자, 부 생성자 모두 안된다.)
  • 클래스나 인터페이스 상속이 가능하다.
  • 클래스 안에 객체 선언이 가능하다.
data class Person(val name: String) {
    object NameComparator: Comparator<Person> {
        override fun compare(p1: Person, p2: Person): Int = p1.name.compareTo(p2.name)
    }
}

위 코드를 보면,

클래스 안에서 객체를 선언하였다.

이를 접근하기 위해서는 Person.NameComparator를 이용하여 접근하면 된다.

 

* object키워드를 자바에서 접근하기 위해서는 INSTANCE를 이용하여 접근 가능하다.

동반 객체(Companion object)

코틀린에는 static 키워드가 존재하지 않고 패키지 수준의 최상위 함수와 객체 선언을 사용할 수 있다.

최상위 함수는 static을 대신할 수 있다. 객체 선언은 최상위 함수가 접근할 수 없는 클래스 안의 private 멤버 변수에 접근할 때 사용할 수 있다.

동반 객체는 companion 키워드를 붙인 클래스 안에 정의 객체이다.

동반 객체의 멤버를 사용하는 구문은 정적 메서드 호출이나 정적 필드 사용과 유사하다. 또한 자신을 둘러싼 클래스의 모든 private 멤버에 접근이 가능하다.

class User private constructor(val nickname: String) {
    companion object { //이름을 지정하지 않으면 동반 객체의 이름은 Companion이다.
        fun newSubscribingUser(email: String) = User(email.substringBefore('@')) //바깥 클래스의 private 멤버 접근 가능
    }
}

//동반 객체의 멤버를 정적 멤버처럼 접근
val user = User.newSubscribingUser("jun@mail.com")

주석으로 보이듯 동반 객체의 이름을 정의해주지 않으면 Companion이 이름으로 사용된다.

이름을 정의해주면 다음과 같다.

class User private constructor(val nickname: String) {
    companion object Facotry{ 
        fun newSubscribingUser(email: String) = User(email.substringBefore('@')) 
    }
}

val user = User.Facotry.newSubscribingUser("jun@mail.com")

동반 객체의 이름을 사용하여 접근이 가능해진다.

동반 객체와 타입 상속

동반 객체도 인터페이스 구현을 할 수 있다.

interface JSONFactory<T> { 
    fun fromJSON(jsonText: String) : T
}

class Person(val name: String) {
    companion object: JSONFactory<Person> {
        override fun fromJSON(jsonText: String): Person {
            return Person(jsonText)
    }
}

fun loadFromJSON(facotry: JSONFactory): T { . . . . }

loadFromJSON(Person) //동반 객체 전달

동반 객체가 인터페이스를 구현하면 컴파일할 때 Person.Companion으로 바뀌게 된다. 이는 loadFromJSON 함수에 사용된다.

동반 객체 확장

동반 객체에 대한 확장 함수도 가능하다.

확장 함수를 사용하려면 비어있는 동반 객체를 선언하고 확장 함수를 선언해야 한다.

class Person(val firstName: String, val lastName: String) { 
    companion object {}
}

fun Person.Companion.fromJSON(json: String ): Person { . . . . }

val p = Person.fromJSON(json) //동반 객체의 확장 함수 실행

객체 식

object 키워드를 사용하여 익명 객체(무명 객체, anonymous object)를 정의한다.

var clickCount = 0

window.addMouseListener(
    object: MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            clickCount++
        }
        . . . .
    }
}

 

object 키워드를 클래스에 사용하는 게 아닌 객체에 사용할 경우 매번 새로운 인스턴스를 생성하게 된다.

또한 object 블록 내에서 로컨 변수 값에 접근할 수 있다.

728x90

댓글