Kotlin

코틀린 object

SKaSha 2019. 8. 2. 16:12

코틀린의 object 키워드를 이용하여 다음 내용들을 해결합니다.

  • 싱글톤 정의
  • 동반 객체(companion object)를 이용한 팩토리 메서드 구현
  • 익명클래스 선언

싱글톤

자바에서의 싱글톤

public class Test {
    private static Test obj;
    private Test() {}
    static Test getInstance() {
        if(obj == null) obj = new Test();
        return obj;
    }
}

코틀린에서의 싱글톤

object Test { }

코틀린에서 object 클래스는 선언과 동시에 객체가 자동으로 생성되고 개발자가 생성 할 수 없으므로 싱글톤 개념이 적용된 클래스입니다.

객체에서 comparator를 여러개 구현할 필요가 없을 경우 싱글톤으로 하나만 만들어 넣고 사용하는 경우가 많습니다.

data class Person(val name: String) {
    object NameComparator : Comparator {
        override fun compare(p1: Person, p2: Person): Int =
            p1.name.compareTo(p2.name)
    }
}

fun main(args: Array<String>) {
    val persons = listOf(Person("KaSha"), Person("Dasom"))
    println(persons.sortedWith(Person.NameComparator))
}

Java에서 object 객체를 호출시에는 INSTANCE란 이름을 통해 호출합니다.

Person.NameComparator.INSTANCE.compare(new Person("KaSha"), new Person ("Dasom"));

companion object

이름이 있는 object 클래스를 최상위에 작성하지 않고 특정 클래스 안에 작성 할 수 있습니다.

class Outer {
    object NestedClass {
        val no: Int = 0
        fun myFun() { }
    }
}

fun main(args: Array<String>) {
    val obj = Outer()
    obj.NestedClass.no    // 에러

    Outer.NestedClass.no
    Outer.NestedClass.myFun()
}

Outer클래스 외부에서 object클래스 내부에 접근할때는 객체를 이용해서 접근하는 것이 아니라, Outer.NestedClass와 같이 클래스명으로 직접 이용해야 합니다.
그 이유는 object 클래스가 자바로 변형될 때는 static 멤버로 변형되기 때문입니다.
하지만 자바의 static 객체처럼 클래스명으로 바로 이용하는 상수변수를 여러개 선언해야 할 때 object 클래스명을 대입해야 하는 번거로움이 있습니다.
이럴때 companion 예약어를 이용하면 object 클래스명을 사용하지 않고 이용하게 해줍니다.

class Outer {
    companion object NestedClass {
        val no: Int = 0
        fun myFun() { }
    }

    fun myFun() {
        no
        myFun()
    }
}

fun main(args: Array<String>) {
    Outer.NestedClass.no
    Outer.NestedClass.myFun()

    Outer.no
    Outer.myFun()
}

즉, companion object를 이용하면 자바의 static과 같은 효과를 낼 수 있습니다.

익명 클래스

익명 클래스를 이용할 때도 object 예약어를 이용합니다.
여기에서 익명클래스는 싱글톤이 아니기 때문에 호출할 때마다 객체가 생성되며 익명클래스 내부에서 외부 클래스의 변수에 접근하여 값을 수정할 수도 있습니다.
자바에서는 익명클래스에서 접근시 해당 변수가 반드시 final이어야 하는것과 차이가 있습니다.

interface ClickListener {
    fun onClick()
}

fun main(args: Array) {
    setClick(object : ClickListener {
        override fun onClick() {
            println("click event!")
        }
    })
}

fun setClick(clickListener: ClickListener) {
    clickListener.onClick()
}

참고

깡샘의 코틀린 프로그래밍 서적