[Kotlin in Action] 15. 코틀린 중첩 클래스

반응형
728x90
반응형

중첩클래스

자바처럼 코틀린에서도 클래스 안에 다른 클래스를 선언할 수 있다. 클래스 안에 다른 클래스를 선언하면 도우미 클래스를 캡슐화하거나 코드 정의를 그 코드를 사용하는 곳에 둘때 유용하다.

 

자바와의 차이점

코틀린의 중첩 클래스는 명시적으로 요청하지않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다는 점이다.

 

 

JAVA

ButtonJava.java
public class ButtonJava implements View {
    @NotNull
    @Override
    public State getCurrentState() {
        return new ButtonState();
    }

    @Override
    public void restoreState(@NotNull State state) {

    }

    /**
     * 중첩 클래스
     */
    public class ButtonState implements State {

    }
}

State 인터페이스를 구현한 ButtonState 클래스를 정의해서 ButtonJava 대한 구체적인 정보를 저장한다.

여기서 ButtonState 직렬화 시도시, NotSerializableException 이 발생한다.
직렬화하려는 변수는 ButtonState 타입의 state 인스턴스인데, 왜 ButtonJava 를 직렬화할 수 없다는 예외가 발생할까?

자바에서 다른 클래스 안에 정의한 클래스는 자동으로 내부 클래스(inner class)가 된다.
이 예제의 ButtonState 클래스는 바깥쪽 ButtonJava에 대한 참조를 묵시적으로 포함한다.
그 참조로 인해 ButtonState 를 직렬화할 수 없다.
ButtonJava을 직렬화할 수 없으므로 버튼에 대한 참조가 ButtonState의 직렬화를 방해한다.

문제를 해결하기 위해서는 ButtonState static 클래스로 선언해야한다.

자바에서 중첩클래스를 static으로 선언하면 클래스를 둘러싼 바깥쪽 클래스에 대한 묵시적인 참조가 사라진다.

public static class ButtonState implements State {}

 

 

Kotlin

코틀린 중첩 클래스에 아무런 변경자가 붙지 않으면 자바 static 중첩 클래스와 같다.

class Button : View {
    /**
     코틀린 중첩 클래스에 아무런 변경자가 붙지 않으면 자바 static 중첩 클래스와 같다.
     이를 내부 클래스로 변경해서 바깥 클래스에 대한 참조를 포함하게 만들고 싶다면, inner 변경자를 붙여야한다.
     */
    class ButtonState : State {

    }

    override fun getCurrentState(): State {
        TODO("Not yet implemented")
    }

    override fun restoreState(state: State) {
        TODO("Not yet implemented")
    }
}

 

이를 내부 클래스로 변경해서 바깥 클래스에 대한 참조를 포함하게 만들고 싶다면, inner 변경자 붙여야한다.

class Button : View {
    inner class ButtonState : State {

    }

    ...
}

 

 

자바와 코틀린의 중첩 클래스와 내부 클래스의 관계

클래스 B 안에 정의된 클래스 A 자바에서는 코틀린에서는
중첩 클래스 (바깥쪽 클래스에 대한 참조를 저장하지 않음) static class A class A
내부 클래스 (바깥쪽 클래스에 대한 참조를 저장함) class A inner class A

 

 

코틀린에서 내부 클래스(inner) -> 바깥쪽 클래스(outer) 참조에 접근하기

this@Outer을 사용한다.

class Outer {
    inner class Inner {
        // 내부 클래스 Inner 안에서 바깥쪽 클래스 Outer 의 참조에 접근하려면 this@Outer 라고 써야한다.
        fun getOuterReference(): Outer = this@Outer
    }
}

 

 

반응형

Designed by JB FACTORY