중첩 클래스와 내부 클래스

중첩 클래스와 내부 클래스

클래스 안에 다른 클래스를 넣을 수 있다는 건 Kotlin이 상속 외에 타입을 구조화하는 방법을 보여주는 좋은 예시예요. 한 클래스를 다른 클래스의 내부에 선언하는 방식, 그리고 inner 키워드가 붙으면 동작이 어떻게 달라지는지 차근차근 살펴볼게요.

출처: Kotlin 공식 문서

본문

클래스는 다른 클래스 안에 중첩할 수 있어요.

class Outer {
    private val bar: Int = 1
    class Nested {
        fun foo() = 2
    }
}

val demo = Outer.Nested().foo() // == 2

인터페이스도 중첩과 함께 사용할 수 있어요. 클래스와 인터페이스의 모든 조합이 가능하죠. 클래스 안에 인터페이스를, 인터페이스 안에 클래스를, 인터페이스 안에 인터페이스를 중첩할 수 있어요.

interface OuterInterface {
    class InnerClass
    interface InnerInterface
}

class OuterClass {
    class InnerClass
    interface InnerInterface
}

내부 클래스

inner로 표시된 중첩 클래스는 바깥 클래스의 멤버에 접근할 수 있어요. 내부 클래스는 바깥 클래스의 객체에 대한 참조를 갖고 있는데요, 그래서 다음과 같이 바깥 클래스의 속성을 바로 읽을 수 있죠.

class Outer {
    private val bar: Int = 1
    inner class Inner {
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo() // == 1

내부 클래스에서 this를 구분하는 방법이 궁금하다면 Qualified this expressions 문서를 참고해요.

익명 내부 클래스

익명 내부 클래스의 인스턴스는 object expression을 사용해서 만들어요.

window.addMouseListener(object : MouseAdapter() {

    override fun mouseClicked(e: MouseEvent) { ... }

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

JVM에서 객체가 함수형 Java 인터페이스(추상 메서드가 하나뿐인 Java 인터페이스)의 인스턴스라면, 인터페이스의 타입을 접두사로 붙인 람다 표현식으로 만들 수 있어요.

val listener = ActionListener { println("clicked") }

더 알아보기