본문 바로가기
Kotlin

[Kotlin] Nested Class와 Inner Class

by 태크민 2025. 2. 27.

자바와 코틀린의 서로 다른 Inner Classes와 Nested Classes

자바든 코틀린이든 중첩 클래스를 활용하는 경우는 매우 흔하게 발생한다.

내가 가진 멤버 클래스를 정의할 때 주로 사용하는데 정의하는 방법은 2가지가 있고, Java와 Kotlin은 전혀 반대로 정의한다.

Java는 명시하지 않으면 inner classes를 나타내고, Kotlin은 명시하지 않으면 Nested classes로 정의한다.

 

Java의 Nested & Inner classes

자바는 중첩 class를 정의하면 기본 Inner classes로 정의한다.

그래서 아래와 같이 Outer class를 정의하고 안에 InnerClass를 정의했을 때 outer라는 String값에 자유자재로 접근이 가능하다.

 

이 코드에 Nested classes로 변경하려면 static을 추가해야 한다. 이제 InnerClass는 묵시적으로 참조하고있던 Outer class 정보가 사라지게 되고, 문법 오류가 발생하게 된다.

 

이를 해결하기 위해서는 아래와 같이 InnerClass의 생성자에 Outer 객체를 넘겨주는 형태로 작성해 해결할 수 있다.

 

Kotlin의 Nested & Inner Classes

코틀린은 완전히 반대로 동작한다.

자바는 기본적으로 중첩클래스를 생성하면 inner class로 정의된다고 하였는데, 코틀린은 기본적으로 nested class로 정의된다.

그렇기 때문에 아래와 같이 적으면 outer 변수에 접근하지 못한다.

 

이를 해결하기 위한 방법은 2가지가 있다.
첫번째 방법은, inner 예약어를 붙여 inner class를 만들어 묵시적으로 Outer를 참조하도록 만드는 것이다.

 

두번째 방법은, 자바에서처럼 생성자에 outer를 전달해주면 해결이 가능하다.

 

정리하면,

위에서 작성한 코드를 표로 정리하면 아래와 같다.

class Outer 안에 정의한 InnerClass Java Kotlin
Nested classes static class InnerClass  class InnerClass (기본)
inner classes class InnerClass (기본) inner class InnerClass 

 

Inner classes는 항상 밖에 있는 Outer가 생성되어야 안에 있는 InnerClas도 생성할 수 있다.

val innerClass = Outer().InnerClass()

 

이렇게 Outer가 생성되고, InnerClas가 생성되면, InnerClas가 Outer의 멤버를 사용치 않아도 불필요하게 Outer는 항상 생성되어야 한다.

 

반면, NestedClass는 밖에 있는 Outer 생성 없이도 독립적인 취급을 받을 수 있다.

val innerClass = Outer.InnerClass()

 


코틀린은 왜 기본적으로 Nested classes를 사용할까? 

코틀린은 자바에서 태어났다고 할 수 있는데, 왜 중첩 클래스의 기본이 서로 다를까?

 

실제로, 자바의 Inner Class에는 크게 3가지 문제가 있다고 한다.

  1. Inner classes를 사용할 경우 직렬화에 문제가 있다.
  2. Inner classes 내부에 숨겨진 Outer class 정보를 보관하게 되고, 결국 참조를 해지하지 못하는 경우가 생기면 메모리 누수가 생길 수 있고, 코드를 분석하더라도 이를 찾기 쉽지 않다.
  3. Inner classes를 허용하는 자바는 Outer를 참조하지 않아도 기본 inner classes이기 때문에 불필요한 메모리 낭비와 성능 이슈를 야기한다.

이러한 문제가 있어서 코틀린에서는 Nested class를 기본으로 해놨던 것이다!

 


안드로이드 RecyclerView를 통해 문제 살펴보기.

RecyclerView.ViewHolder는 Inner classes보다는 Nested classes 또는 top level로 만드는 게 좋다고 생각한다.

  • 항상 하나의 어댑터에서 만 활용하는 건 아니다.
  • RecyclerView는 실제로 화면 사이즈보다 많이 onCreateViewHolder가 호출되고 만들어진다.

화면 사이즈 보다 많이 만들어지는데, Inner classes로 정의한다면 생성되는 객체마다 묵시적으로 Outer class를 항상 참조하게 된다.

하지만 안드로이드는 Activity/Fragment에서 RecyclerView를 사용하고 있고, 이들이 onDestroy 호출되면 Adapter 역시 함께 사라지고, 그럼 ViewHolder들도 함께 사라지기 때문에 큰 문제는 없다.

꼭 필요하지 않다면 코틀린 기본 값인 Nested classes인 기본 상태를 굳이 inner를 추가할 필요는 없다고 생각하고, 좀 더 좋은 접근법인 top level로 작성하는 것도 고려하는 게 좋다고 생각한다.


정리

  • 자바에서의 문제점 때문에 코틀린에서는 그 점을 해결하기 위해서 기본적으로 Nested classes인 것이다. 다 이유가 있다.
  • outer의 멤버를 참고할 필요가 없다면 inner 예약어를 사용하지 않는게 좋다.
  • Inner class는 필요할 때 쓰는게 좋은데, 잘 모르겠다면 Nested class를 쓰자!
  • ViewHolder의 경우 안드로이드의 생명주기 때문에 자바에서의 문제점들이 해결이 되지만, 그래도 ViewHolder가 호출될 때 불필요한 outer 클래스도 만들지 않기 위해선 inner를 쓰지말자.

 


참고자료

https://velog.io/@huijiny/Kotlin-Inner-Nested-classes

 

[Kotlin] Inner & Nested classes

무려 한달만의 포스팅이다.그동안 ssafy 마지막 최종 프로젝트 때문에 바빴고, 방학을 기념삼아 여행도 좀 다녀오면서 블로그에 소홀했다.여행에서 돌아온 뒤에 EcoMode라는 개인 프로젝트를 시작

velog.io

https://thdev.tech/kotlin/2020/11/17/kotlin_effective_11/

 

Kotlin과 Java의 Nested and Inner Classes를 알아보고, Nested classes를 왜 사용해야 하는지 알아본다. |

I’m an Android Developer.

thdev.tech