자바의 중첩 클래스 문제와 코틀린의 중첩 클래스
자바에서는 내부에 선언되는 중첩 클래스에서 기본적으로 바깥쪽 클래스의 변수를 참조할 수 있었다. 예를 들어 다음과 같이 OuterClass와 InnerClass가 있는 경우 InnerClass의 함수인 getOuterClassValue에서 OuterClass의 변수인 outerClassValue를 참조할 수 있었다.
public class OuterClass {
String outerClassValue = "outerClassValue";
class InnerClass {
String getOuterClassValue() {
return outerClassValue;
}
}
}
하지만, 이 방식은 내부의 클래스에서 항상 외부의 클래스에 대한 참조를 유지한다는 점에서 문제가 있었다. 내부 클래스에서 외부 클래스에 대한 참조를 유지하는 것은 의도치 않은 메모리 누수를 발생 시킬 수 있으며, 내부 클래스의 인스턴스가 외부 클래스의 인스턴스를 참조하고 있을 때 외부 클래스의 인스턴스는 가비지 컬렉터에 의해 정리될 수도 없다.
이러한 문제를 해결하기 위해 코틀린에서는 중첩 클래스(내부 클래스)에서 기본저으로 외부 클래스에 대한 참조를 가지지 않는다. 한 번 다음과 같이 코틀린 코드를 작성해보자.
class OuterClass {
var outerClassValue = "outerClassValue"
class InnerClass {
fun getOuterClassValue(): String {
return outerClassValue
}
}
}
그러면 다음과 같은 오류가 나온다.
Unresolved reference: outerClassValue
번역: outerClassValue에 대한 참조가 없습니다.
바로 InnerClass에서 OuterClass의 값을 참조할 수 없기 때문이다.
코틀린의 중첩 클래스를 inner class로 선언해 외부 클래스에 대한 참조 가지기
코틀린은 자바와 100% 호환된다는 점을 기억하자. 코틀린에서는 위와 같이 기본적으로 중첩 클래스는 외부 클래스를 참조할 수 없도록 했지만, 특별한 키워드 inner을 클래스 앞에 붙이면 외부 클래스에 대한 참조를 가지도록 만든다.
위에서 다룬 InnerClass의 class 앞에 inner 키워드를 붙여보자.
class OuterClass {
var outerClassValue = "outerClassValue"
inner class InnerClass {
fun getOuterClassValue(): String {
return outerClassValue
}
}
}
그러면 inner class로 선언된 InnerClass 클래스는 OuterClass에 대한 참조를 가져 outerClassValue에 대한 접근이 가능해진다.
정리
- 코틀린의 중첩 클래스는 기본적으로 외부 클래스에 대한 참조를 가지지 않는다.
- 코틀린의 중첩 클래스가 외부 클래스에 대한 참조를 가지려면 inner class 로 선언돼야 한다.
개인적인 의견
하나의 클래스 아래에 여러 클래스가 생기면서 코드가 망가지고 의도치 않은 메모리 릭이 발생하는 것을 꽤 보다 보니, 개인적으로는 외부 객체에 대한 참조를 가지는 객체를 만들려면 별도 객체를 만드는 것이 좋다고 생각한다. 예를 들어 외부에서의 OuterClass에 대한 참조를 가지는 InnerClass 객체는 다음과 같이 더욱 명확하게 만드는 것이 좋은 것 같다.
class OuterClass {
var outerClassValue = "outerClassValue"
}
class InnerClass(
private val outerClass: OuterClass
) {
fun getOuterClassValue(): String {
return outerClass.outerClassValue
}
}