본문 바로가기

프로그래밍/kotlin

코틀린 - 오브젝트 표현식 및 선언

반응형

때로는 새로운 클래스를 명시 적으로 선언하지 않고 클래스를 약간 수정 한 객체를 만들어야합니다. 자바는 

익명의 내부 클래스

 로 처리합니다 코틀린은 

객체 표현

 과 

객체 선언

 으로이 개념을 약간 일반화합니다 .

오브젝트 식

어떤 타입 (또는 타입)으로부터 상속받은 익명의 클래스의 객체를 생성하기 위해 다음과 같이 작성합니다 :

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

    override fun mouseEntered(e: MouseEvent) {
        // ...
    }
})

 상위타입이 생성자를 가지면 알맞은 생성자 파라미터를 전달되어야합니다. 많은 수퍼 유형은 콜론 뒤에 쉼표로 구분 된 목록으로 지정 될 수 있습니다.

open class A(x: Int) {
    public open val y: Int = x
}

interface B {...}

val ab: A = object : A(1), B {
    override val y = 15
}

만일 우연히, "객체"을 필요로하고, 수퍼 타입이 없다면, 다음 코드를 사용할수  있습니다 :

fun foo() {
    val adHoc = object {
        var x: Int = 0
        var y: Int = 0
    }
    print(adHoc.x + adHoc.y)
}

익명 객체는 로컬 및 개인 선언에서만 유형으로 사용할 수 있습니다. 익명 객체를 공용 함수의 반환 유형 또는 공용 속성의 유형으로 사용하는 경우 해당 함수 또는 속성의 실제 유형은 익명 객체의 선언 된 상위 유형이거나 

Any

상위 유형을 선언하지 않은 경우입니다. 익명 객체에 추가 된 멤버는 액세스 할 수 없습니다.

class C {
    // Private function, so the return type is the anonymous object type
    private fun foo() = object {
        val x: String = "x"
    }

    // Public function, so the return type is Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // Works
        val x2 = publicFoo().x  // ERROR: Unresolved reference 'x'
    }
}

Java의 익명 내부 클래스와 마찬가지로 객체 표현식의 코드는 둘러싼 범위의 변수에 액세스 할 수 있습니다. (Java와 달리 최종 변수에만 국한되지 않습니다.)

fun countClicks(window: JComponent) {
    var clickCount = 0
    var enterCount = 0

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

        override fun mouseEntered(e: MouseEvent) {
            enterCount++
        }
    })
    // ...
}

오브젝트 선언

싱글 톤

 은 매우 유용한 패턴이며, 스칼라 (Scala) 이후의 코 틀린 (Kotlin)은 싱글 톤을 선언하기 쉽게 만든다.

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ...
    }

    val allDataProviders: Collection<DataProvider>
        get() = // ...
}

이를 

오브젝트 선언

 이라고하며 

오브젝트

 키워드 다음에 항상 이름이 있습니다. 변수 선언과 마찬가지로 객체 선언은 표현식이 아니며 대입 문의 오른쪽에서 사용할 수 없습니다.객체를 참조하기 위해 이름을 직접 사용합니다.

DataProviderManager.registerDataProvider(...)

이러한 객체는 수퍼 유형을 가질 수 있습니다.

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ...
    }

    override fun mouseEntered(e: MouseEvent) {
        // ...
    }
}

참고

 : 객체 선언은 로컬 일 수 없으며 (즉, 함수 내에 직접 중첩 될 수 있지만) 다른 객체 선언 또는 비 내부 클래스에 중첩 될 수 있습니다.

컴패니언 오브젝트

클래스 내의 객체 선언은 

companion

 키워드 로 표시 할 수 있습니다 .

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

클래스 이름을 한정자로 사용하여 컴패니언 개체의 멤버를 호출 할 수 있습니다.

val instance = MyClass.create()

컴패니언 개체의 이름은 생략 할 수 있습니다.이 경우 이름 

Companion

이 사용됩니다.

class MyClass {
    companion object {
    }
}

val x = MyClass.Companion

컴패니언 객체의 멤버가 다른 언어의 정적 멤버처럼 보이더라도 런타임에는 여전히 실제 객체의 인스턴스 멤버이며 예를 들어 인터페이스를 구현할 수 있습니다.

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


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

그러나 

@JvmStatic

주석 을 사용하는 경우 JVM에서 컴패니언 객체의 멤버를 실제 정적 메서드 및 필드로 생성 할 수 있습니다 자세한 내용은 

Java 상호 운용성

 섹션을 참조하십시오.

오브젝트 식과 오브젝트 선언의 세만틱  차이

객체 표현과 객체 선언 사이에는 중요한 의미 상의 차이가 있습니다.

  • 객체 표현은 사용되는 곳에서 즉시 실행되고 초기화 됩니다.
  • 객체 선언은 처음 액세스 할 때 느리게 초기화 됩니다.
  • 동등한 객체는 대응하는 클래스가로드 (해결)되었을 때에 초기화되어 Java static initializer의 시멘틱스에 일치합니다.

 

반응형