본문 바로가기
프로그래밍/Kotlin

중첩클래스 사용이유

by Youngs_ 2021. 11. 26.

중첩클래스(NestedClass)는 외부에 선언하는 일반 클래스와 다를바없다. 하지만 중첩클래스를 사용하는 이유는 class의 private에 별다른 제약없이 접근할수있기때문에 사용한다.

class OuterClass{
  companion object{
    private val a = 1
    private val d = 2
  }
  private val b = 2
  class NestedClass{
    private val c = 3
    companion object{
      private val d = 4
      fun getA1() = a
      fun getA2() = OuterClass.a
      fun getA3() = OuterClass.Companion.a
      // 에러 : Unresolved reference: b
      fun getB() = b
      // 에러 : Unresolved reference: c
      fun getC() = c
      fun getD1() = d
      fun getD2() = OuterClass.d
      fun getD3() = OuterClass.Companion.d
    }
    fun getA1() = a
    fun getA2() = OuterClass.a
    fun getA3() = OuterClass.Companion.a
    // 에러 : Unresolved reference: b
    fun getB() = b  
    fun getC() = c
    fun getD1() = d
    fun getD2() = OuterClass.d
    fun getD3() = OuterClass.Companion.d
  }
}
fun main(args: Array<String>) {
  // -- (1)
  println(OuterClass.NestedClass.getA1())
  // -- (2)
  println(OuterClass.NestedClass.getA2())
  // -- (3)
  println(OuterClass.NestedClass.getA3())
  // -- (4)
  println(OuterClass.NestedClass.getD1())
  // -- (5)
  println(OuterClass.NestedClass.getD2())
  // -- (6)
  println(OuterClass.NestedClass.getD3())
  val i = OuterClass.NestedClass()
  println(i.getA1()) // -- (7)
  println(i.getA2()) // -- (8)
  println(i.getA3()) // -- (9)
  println(i.getC()) // -- (10)
  println(i.getD1()) // -- (11)
  println(i.getD2()) // -- (12)
  println(i.getD3()) // -- (13)
}

 

위 코드를 보면 OuterClass에 companion object의 private 멤버 a, d 속성이 정의되어 있습니다. OuterClass 자신에는 b 속성이 정의되어 있습니다. NestedClass를 보면 자신의 속성 c가 있고 companion object에는 d가 정의되어 있습니다. 이때 NestedClass의 companion object에 정의된 getA(), getD() 메소드는 각각 OuterClass와 NestedClass의 companion object 속성에 접근하기 때문에 문제없으나 나머지 getB(), getC() 메소드는 에러가 납니다.

 

main() 함수에 보면 주석 (2), (3) 의 결과는 1임을 금방 알 수 있습니다. 하지만 (1)의 결과도 1입니다. NestedClass의 companion object에는 a가 없으므로 자동으로 OuterClass의 companion object의 a를 참조하게 됩니다.

 

그럼 (4)의 결과는 2일까요? 4일까요? 답은 4입니다. 왜냐하면 자신의 companion object의 속성 d가 이미 있기 때문에 (1)의 결과와 다르게 OuterClass companion object의 d는 섀도잉(Shadowing, 가려짐) 되기 때문입니다.

주석 (5), (6)는 NestedClass의 companion object의 d가 아닌 섀도잉된 OuterClass의 companion object의 d에 직접 접근하기 위해 OuterClass.d 또는 OuterClass.Companion.d를 썼습니다. 결과는 2입니다.

 

이제 companion object와 함께 중첩클래스를 쓰는 이유가 명확해졌습니다. OuterClass에 정의된 companion object의 private 속성에 제약 없이 접근이 가능한 다른 클래스가 필요한 경우 중첩클래스를 쓰면 됩니다. 이렇게 되면 클래스간 공유하는 필요한 로직이나 값이 외부에 노출되지 않고 내부에서만 처리하기 때문에 효율적인 정적 데이타 은닉과 기능의 캡슐화가 가능해집니다.

댓글