반응형

자바에서는 중첩 클래스를 다룰 때 크게 static이 붙느냐 안 붙느냐로 구분하여 사용했었습니다.

그렇다면 static 키워드가 사라진 코틀린에서는 중첩 클래스에 대해 어떻게 처리하고 있을까요?

 

이번 포스팅에서는 자바와 비교하여 코틀린에서는 어떻게 중첩 클래스를 사용할 수 있는지 살표 보도록 하겠습니다.

 

어떤 키워드도 붙이지 않으면 기본적으로 static nested class이다!

우리가 먼저 살펴볼 것은 static 중첩 클래스입니다.

먼저 자바 코드를 통해 예를 들어보겠습니다.

 

A.java

public class A {
    static class B {
        int num;
    }
}

위 자바 코드에서 B 객체에 대한 인스턴스를 생성하기 위해서는 아래와 같이 선언해주면 됩니다.

B b = new A.B();

이처럼 static 중첩 클래스로 정의하게 되면 바깥 클래스의 인스턴스에 의존하지 않고 독립적으로 B 클래스에 대한 인스턴스를 생성할 수 있습니다.

 

그리고 코틀린에서는 이러한 static nested class를 기본으로 제공합니다.

이번에는 위에서 살펴본 java 코드를 코틀린으로 변환해보겠습니다.

 

A.kt

class A {
    class B {
        var num: Int = 0
    }
}

fun main() {
    val b = A.B()
}

 

어렵지 않죠? 접근할 수 있는 범위 또한 자바와 같은 맥락으로 바라보시면 됩니다.

B 클래스는 바깥의 A 클래스의 인스턴스에 종속적이지 않기 때문에 A 클래스의 인스턴스 변수에 대해 접근할 수 없습니다.

 

예를 들어 아래 코드에서 A 클래스 내에서 B 클래스의 bNum 변수를 접근하거나 B 클래스 내에서 A 클래스의 aNum을 가져오는 코드는 컴파일 에러가 발생합니다.

class A {
    val aNum = 10

    fun getBnum() {
        print(bNum)  // impossible!
    }
    
    class B {
        var bNum = 0
        fun getAnum() {
            println(aNum)  // impossible!
        }
    }
}

한 마디로, A 클래스 내에 B 클래스를 정의하지만 사실상 서로 독립된 메모리를 사용한다고 보시면 되겠습니다.

 

인스턴스 멤버 클래스를 만들기 위한 방법 - inner 키워드

앞서 살펴본 static 중첩 클래스는 바깥 클래스와 중첩 클래스 간의 데이터가 공유되지 않고 독립적으로 이루어졌습니다.

하지만 프로그래밍을 하다보면 바깥 클래스와 중첩 클래스 간에 데이터를 공유하는 것이 필요할 때가 많은데요. 그럴 때 사용해야 하는 것이 바로 inner class 입니다.

 

마찬가지로 java 코드로 먼저 살펴보겠습니다.

 

A.java

public class A {
    class B {
        int num;
    }
}

 

이번에는 B 클래스 앞에 static 키워드가 붙지 않았습니다.

이렇게 정의할 경우 B 클래스의 인스턴스를 생성하기 위해서는 다음과 같이 A 클래스의 인스턴스를 반드시 필요로 합니다.

B b = new A().B();

 

코틀린에서는 이렇게 바깥 클래스의 인스턴스에 의존적인 중첩 클래스를 만들기 위해서는 특별히 inner 키워드를 class 앞에 붙여줘야 합니다.

 

마찬가지로 위 java 코드를 그대로 코틀린 코드로 변환해보겠습니다.

 

A.kt

class A {
    inner class B {
        var num: Int = 0
    }
}

fun main() {
    val b = A().B()
}

 

인스턴스 멤버 클래스의 경우 바깥 클래스의 프로퍼티와 함수에 접근할 수 있습니다.

단, 여전히 A 클래스에서 B 클래스의 함수를 마음대로 사용할 수는 없습니다.

 

A.kt

class A {
    val aNum = 10

    fun getBnum() {
        print(bNum)  // impossible!
    }

    inner class B {
        var bNum = 0
        fun getAnum() {
            println(aNum)  // possible!
        }
    }
}

 

그렇다면 중첩 클래스에서 this 키워드는 어떻게 사용하면 될까요?

자바에서는 클래스이름.this 표현으로 특정 클래스에 대한 this를 설정할 수 있었습니다.

그러나 코틀린에서는 조금 다릅니다.

 

코틀린에서는 this@클래스이름 표현으로 this 키워드가 가리키는 대상에 대해 명확하게 대상을 선정할 수 있습니다.

 

A.kt

class A {
    val num = 10

    inner class B {
        val num = 5
        fun getAnum() {
            println(this@A.num)  // 10
            println(this@B.num)  // 5
        }
    }
}

 

반응형
반응형