본문 바로가기

Kotlin/Basic

[Kotlin] 내부(Inner class)와 중첩 클래스(Nested class)

자바에서는 A클래스 안에 B 클래스를 정의하면 B클래스는 자동으로 내부 클래스가 된다.

하지만 코틀린에서는 반대이다. 한 클래스 안에 다른 클래스를 정의하면 기본적으로는 중첩 클래스가 되고, 내부 클래스로 만들고 싶다면 inner 키워드로 클래스는 선언해야 한다.

내부 클래스는 기본적으로 외부 클래스를 참조하게 되지만, 중첩 클래스는 그렇지 않다.

다음의 코드들을 보자.

class Outer{
    private val bar:Int = 1
    class Nested{
        fun foo()=bar // error! bar가 아닌 다른 값으로 변경해 줘야한다.
    }
}

fun main(){
    print(Outer.Nested().foo())
}

먼저 중첩(Nested) 클래스다.

중첩 클래스는 외부 클래스(위 코드에서는 Outer)를 참조하지 않기 때문에 Outer.Nested().foo()의 값이 Outer 클래스의 필드인 bar의 값을 받지 못한다.

class Outer{
    private val bar:Int = 1
    inner class Inner{
        fun foo()=bar
    }
}

fun main(){
    print(Outer().Inner().foo())
}

반면, 내부 클래스에서는 외부 클래스를 항상 참조하기 때문에 Outer().Inner().foo() (여기서 잘 보면 Outer도 ()를 포함하고 있다. Outer가 참조되기 위해 객체를 생성하는 것)의 값이 bar의 값인 1이 된다.

객체를 항상 참조하고 있다는 것은 어떤 의미일까?

객체가 삭제되는 시점은 객체가 더 이상 사용되지 않는 시점이다. 그런데 내부 클래스를 사용하면 항상 외부 클래스의 객체를 참조하기 때문에, 객체가 적절한 시점에 삭제되지 못하고 메모리 누수가 발생한다.

이러한 누수가 위험한 이유는, 명시적(컴파일 시 오류가 발생하는 등 명시적으로 알 수 있는 것)인 것이 아니라 암묵적(프로그래머가 발견하기 전까지는 알 수 없는 것)인 것이기 때문이다.

따라서 특별한 경우가 아니라면 내부 클래스 사용을 지양하고 중첩 클래스를 사용하는 것이 권장된다.


Uploaded by N2T