가시성 변경자 (접근 제어자)
코드 기반에 있는 선언에 대한 클래스 외부 접근을 제어한다.
어떤 클래스의 구현에 대한 접근을 제한함으로써 그 클래스에 의존하는 외부 코드를 깨지 않고도 클래스 내부 구현이 변경 가능하다.
Kotlin 접근 제어자 종류
- public(기본 가시성)
- internal
- protected
- private
아무 변경자가 없는 경우는 public 이다.
| 변경자 | 클래스 멤버 | 최상위 선언 |
| public | 모든 곳에서 볼 수 있다. | 모든 곳에서 볼 수 있다. |
| internal | 같은 모듈 안에서만 볼 수 있다. | 같은 모듈 안에서만 볼 수 있다. |
| protected | 하위 클래스 안에서만 볼 수 있다. | (최상위 선언에 적용할 수 없음) |
| private | 같은 클래스 안에서만 볼 수 있다. | 같은 파일 안에서만 볼 수 있다. |
Kotlin 과 Java의 차이
- 자바의 기본 가시성인 패키지 전용(package-private)이 없다. 코틀린은 패키지를 네임스페이스를 관리하기 용도로만 사용한다.
- 패키지 전용 가시성에 대한 대안으론 interanl 이라는 새로운 가시성이 존재한다. (internal : 모듈 내부에서만 볼수 있음)
- 최상위 선언에 대해 private 을 허용 한다는 점.
- 자바에서는 같은 패키지 안에서 protected 멤버에 접근 가능하지만, 코틀린에서는 그렇지 않다. 코틀린은 오직 어떤 클래스나 그 클래스를 상속한 클래스 안에서만 보인다.
- 클래스를 확장한 함수는 그 클래스의 private 이나 protected 멤버에 접근할 수 없다.
- 코틀린에서는 외부 클래스가 내부 클래스나 중첩된 클래스의 private 멤버에 접근할 수 없다.
내부 클래스와 중첩된 클래스
자바와 코틀린의 차이는 중첩 클래스는 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다는 점이다.
예시 코드를 통해서 개념을 이해해보자.
// 직렬화 할 수 있는 State(상태)가 있는 뷰 선언
interface State : java.io.Serializable
interface View {
fun getCurrentState() : State
fun reStoreState (State: State) {}
}
위 코드를 구현한 코틀린과 자바 코드를 가지고 비교해보자.
[Java 코드]
// Java 에서 내부 클래스를 사용해 View 구현해보기
public class Button implements View {
@Override
public State getCurrentState() {
return new ButtonState(); // ButtonState의 새 인스턴스로 만든다.
}
@Override
public void reStoreState(State state) {
...
}
// State 인터페이스를 구현한 클래스를 정의해서 Button에 대한 구체적인 정보를 저장한다.
public class ButtonState implements State {
....
}
}
위 자바 코드는 잘못 됐다. 무엇이 잘못 됐을까?
선언한 버튼의 상태를 직렬화하면 java.io.NotSerializableException : Button 이라는 오류가 발생한다.
자바에서 다른 클래스 안에 정의한 클래스는 자동으로 내부 클래스가 된다는 사실을 알 것이다.
ButtonState 클래스는 바깥쪽 Button 클래스에 대한 참조를 묵시적으로 포함하게 된다.
그 참조로 인해 ButtonSate의 직렬화를 방해한다.
이 문제를 해결하기 위해선, ButtonState 클래스에 static 클래스를 선언해야 한다.
그러면 중첩 클래스로 인지를 해서, ButtonState 클래스를 둘러싼 Button 클래스에 대한 묵시적인 참조가 사라지게 된다.
코틀린 코드는 정반대이다. 코틀린 코드를 확인해보자.
[Kotlin]
// Kotlin 에서 중첩 클래스를 사용해 코틀린에서 View 구현하기
class Button : View {
override fun getCurrentState(): State = ButtonState()
override fun reStoreState(State: State) {
super.reStoreState(State)
}
class ButtonState : State {
//...
}
}
코틀린 중첩 클래스에 아무런 변경자가 붙지 않는다면, 자바 static 중첩 클래스와 같다.
이를 내부 클래스로 변경해서 바깥쪽 클래스에 대한 참조를 포함하게 만들고 싶다면? inner 변경자를 붙이면 된다.
| 클래스 B안에 정의된 클래스 A | 자바에서 | 코틀린에서 |
| 중첩 클래스 | static class A | class A |
| 내부 클래스 | class A | inner class A |
코틀린에서 바깥쪽 클래스의 인스턴스를 가리키는 참조를 표기하는 방법도 자바와 다르다.
내부 클래스 Inner 안에서 바깥쪽 클래스 Outer의 참조에 접근하려면 this@Outer 라고 작성해야 한다.

class Outer {
inner class Inner {
fun getOuterReference() : Outer = this@Outer
}
}'Language > Kotlin' 카테고리의 다른 글
| [Kotlin IN ACTION] - Kotlin 클래스 선언(주 생성자, 프로퍼티) (0) | 2022.07.25 |
|---|---|
| [Kotlin IN ACTION] - Kotlin sealed 클래스 (0) | 2022.07.25 |
| [Kotlin IN ACTION] - Kotlin open / final / abstract 상속 제어(접근) 변경자 (0) | 2022.07.22 |
| [Kotlin IN ACTION] - Kotlin Interface(인터페이스) (0) | 2022.07.22 |
| [Kotlin IN ACTION] - Kotlin 로컬 함수와 확장 (0) | 2022.07.21 |