[Kotlin] Inner & Nested classes

Heejin Ryu·2021년 6월 16일
2

Kotlin

목록 보기
2/2

무려 한달만의 포스팅이다.

그동안 ssafy 마지막 최종 프로젝트 때문에 바빴고, 방학을 기념삼아 여행도 좀 다녀오면서 블로그에 소홀했다.

여행에서 돌아온 뒤에 EcoMode라는 개인 프로젝트를 시작했는데, 코드 리뷰를 받는 중에 이런 리뷰를 받았다.

Recycler view 내에서 ViewHolder를 inner class로 정의 했는데, 그에 따른 리뷰였다.

그래서!!!! 오늘은 kotlin의 inner class와 nested class에 대해서 공부하고(첨주주신 링크를 참고하여), 수정 후 결과를 공유해보려고 한다.


Inner and Nested classes

Java의 Nested & Inner classes

자바는 기본적으로 중첩 클래스를 생성하면 inner class라고 한다. 그래서 아래와 같이 Outer class를 정의하고 안에 InnerClass를 정의했을 때 outer라는 String값에 자유자재로 접근이 가능하다.

이를 Nested class로 변경하면 class InnerClass{ 앞에 static을 붙이면 되는데, 그 결과는 아래와 같다. 'outer'변수가 cannot be referenced 되었다고 한다.

이를 해결하기 위해서는 아래와 같이 InnerClass 생성자에 Outer를 넘겨 out.outer로 접근하여 프린트하면된다!

Kotlin의 Nested & Inner Classes

코틀린은 자바와 정. 반. 대. 이다. 자바는 기본적으로 중첩클래스를 생성하면 inner class로 정의된다고 하였는데, 코틀린은 기본적으로 nested class로 정의된다. 그렇기 때문에 아래와 같이 적으면 outer 변수에 접근하지 못한다.

이를 해결하기 위해서는
첫번째로, inner 예약어를 붙여 inner class를 만들어 묵시적으로 Outer를 참조하도록 만들 수 있고,

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

Java & Kotlin의 Nested classes

nested classes는 묵시적인 참조를 하지 않기 때문에, Outer와 InnerClass는 각각 다른 클래스로 취급받는다고한다.

val innerClass = Outer.InnerClass()

코틀린의 경우 위의 코드를 통해 생성된다.

InnerClass는 바깥에 있는 Outer가 생성되어야 생성된다. 이럴경우 만약 InnerClass가 Outer의 멤버변수 등을 필요치 않을 경우에도 Outer를 생성해야하는 불필요한 상황이 나타날 수 있다.

여기서 의문이 생길 수 있다.

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

Java의 Inner Classes의 문제점

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

무릎 탁!🤭 이러한 문제가 있어서 코틀린에서는 Nested class를 기본으로 해놨구나!🥺 결국, 기존에 자바가 가지고 있던 문제점을 코틀린에서는 기본적으로 해결해서 나온건데 거기에 내가 inner를 굳이굳이 붙인것..!(물론 inner가 필요할 때가 있겠지만)

Android RecyclerView 내부 코드에서.

참조한 블로그에서는 친절하게 android recyclerView 내부설계도 함께 봐주고 있다. 그 중에서 내가 실수한 ViewHolder 클래스만 참고해보았다.

ViewHolder

뷰 홀더의 경우(code in Java) static class로 정의하면서 inner class가 아니도록 정의하였는데, kotlin에서는 아무것도 붙이지 않은 기본 정의가 nested class이므로 Inner 예약어를 안쓰면 된다. 그렇게 된다면 이 ViewHolder 클래스는 독립적으로 사용이 가능하다는 의미인데, 블로그의 저자는 Inner classes보다는 Nested classes나 top level로 만드는것이 좋다고 생각한다. 이유는 이 뷰 홀더를 여러 어댑터에서 사용할 수도 있고, 리사이클러뷰는 실제로 화면 사이즈보다 많이 onCreateViewHolder가 호출되고 만들어지는데, InnerClasses로 정의하면 그 객체마다 묵시적으로 Outer class를 참조하게 되기 때문이다.

안드로이드에서는 activity/fragment가 onDestroy되면 Adapter역시 사라지기 때문에 큰 문제는 없다고 하지만, 꼭 필요하지 않다면 코틀린에서 이미 위험을 방지한 코드를 inner 예약어를 붙이면서 사용할 필요는 없다고 생각한다!

정리

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

Reference

https://thdev.tech/kotlin/2020/11/17/kotlin_effective_11/
https://kotlinlang.org/docs/nested-classes.html

profile
Chocolate lover🍫 & Junior Android developer🤖

0개의 댓글