References: Do it! 코틀린 프로그래밍

코틀린에서의 내부 클래스에 대해 알아봅니다.

 

 

1. 내부 클래스

 

내부 클래스는 클래스 내부에 클래스를 다시 정의하는 것을 말합니다.

내부 클래스는 독립적인 클래스로 정의하기 모호한 경우나 한 클래스의 내부에서만 사용하고 외부에선 접근할 필요가 없는 클래스를 정의하기 위해 사용합니다.

단, 이러한 내부 클래스는 남용하면 클래스의 의존성이 커지고 가독성이 저하되므로 주의가 필요합니다.

 

 

2. 중첩(Nested) 클래스

 

코틀린에서 내부 클래스를 정의하기 위한 방법 중 하나입니다.

코틀린에서 중첩 클래스는 기본적으로 적적 클래스처럼 다뤄집니다. 즉 객체 생성 없이 접근이 가능합니다.

 

다음 예제를 통해 확인해 보도록 하겠습니다.

 

class Outer{
    val ov = 5
    class NestedNested {
        val nv = 10
        fun greeting() = "[Nested] Hello! $nv"
    }
    fun outside() {
        val msg = Nested().greeting()
        println("[Outer] $msg, ${Nested().nv}")
    }
}
fun main() {
    val output = Outer.Nested().greeting()
    println(output)
    val outer = Outer()
    outer.outside();
}

 

  • class Nested: 중첩 클래스를 정의합니다.
  • $nv: 내부의 nv는 접근 가능하나 외부의 ov는 접근할 수 없습니다.
  • Nested().greetring: 정적 클래스 취급으로 객체 생성 없이 사용 가능합니다.
  • val outer = Outer(): 외부 클래스는 객체를 생성해야 접근 가능합니다.

위 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

만약 외부 내부 클래스에서 외부 클래스에 접근하고 싶으면 외부 클래스에 컴패니언 객체를 정의하면 됩니다.

컴패니언 객체는 static처럼 접근이 가능하므로 중첩 클래스에서 접근이 가능합니다.

 

예를 들어 다음과 같은 경우엔 중첩 클래스에서 외부 클래스의 프로퍼티에 접근할 수 있습니다.

 

class Outer{
    val ov = 5
    class Nested{
        val nv = 10
        fun gretting() = "[Nested] Hello! $nv"
        fun accessOuter() = println("Country: $country")
    }
    fun outside() {
        val msg = Nested().gretting()
        println("[Outer] $msg, ${Nested().nv}")
    }
    companion object{
        const val country = "Korea"
    }
}

 

  • const val country: 외부에 존재하는 클래스에 컴패니언 객체를 선언하였습니다.

위와 같이 컴패니언 객체 내부의 프로퍼티는 중첩 클래스에서 접근할 수 있습니다.

   

 

3. 이너(Inner) 클래스

 

이너 클래스는 inner라는 선언자를 통해 정의할 수 있습니다.

inner를 통해 선언된 이너 클래스는 외부 클래스의 멤버에 접근할 수 있습니다.

심지어 private멤버까지도 사용할 수 있습니다.

 

다음 예시를 통해 확인해 보도록 하겠습니다.

 

class SmartPhone(val model: String){
    private val cpu = "Snapdragon"
    inner class ExternalStorage(val size: Int){
        fun getInfo() = "${model}: Installed on $cpu with ${size}${size} GB"
    }
}
fun main() {
    val mySdcard = SmartPhone("Note9").ExternalStorage(256)
    println(mySdcard.getInfo())
}

 

  • inner class ExternalStorage: 이너 클래스에서는 외부 클래스의 멤버에 접근 가능합니다.

위의 코드를 실행시키면 다음과 같은 결과를 확인할 수 있습니다.

이너 클래스에선 외부 클래스의 private멤버를 사용할 수 있는 것을 확인할 수 있습니다.

 

 

4. 익명 객체

 

자바에서는 익명 이너 클래스를 통해 일회용 객체를 생성하였습니다.

코틀린에서는 object 키워드를 사용하는 익명 객체로 같은 기능을 수행할 수 있습니다.

자바와의 차이점은 다중 인터페이스를 통한 구현이 가능하는 것입니다.

 

다음 예제를 통해 확인해 보도록 하겠습니다.

 

interface SwitcherSwitcher { fun on(): String }
class SmartPhone(val model: String){
    private val cpu = "Snapdragon"
    inner class ExternalStorage(val size: Int){ fun getInfo() = "${model}: Installed on $cpu with ${size}GB" }
    fun powerOn(): String {
        class Led(val color: String){ fun blink(): String = "Blinking $color on $model" }
        val powerStatus = Led("Red")
        val powerSwitch = object: Switcher {
            override fun on(): String { return powerStatus.blink() }
        }
        return powerSwitch.on()
    }
}
fun main() {
    val myPhone = SmartPhone("Note9")
    myPhone.ExternalStorage(256)
    println(myPhone.powerOn())
}

 

  • interface switcher: 인터페이스 선언
  • object: Switcher: 익명 객체 사용
  • override fun on: 인터페이스의 메서드 구현
  • powerSwitch.on(): 익명 객체의 메서드 사용

위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

 

 

 

 

반응형

+ Recent posts