jujuwon
시크릿주주
jujuwon
전체 방문자
오늘
어제
  • 분류 전체보기 (106)
    • 🔠 프로그래밍언어 (35)
      • ☕️ Java (19)
      • 🐠 Python (15)
      • 🍠 Kotlin (1)
    • 🔙 Backend (16)
      • 🌿 Springboot (12)
      • 🐳 Docker (1)
      • ☁️ AWS (3)
    • 💼 CS (12)
      • 📶 Network (12)
    • 🕹 알고리즘 (14)
      • 📑 스터디 (2)
      • 💁🏻‍♂️ 백준 (9)
      • 👨🏼‍🔬 프로그래머스 (3)
    • 📚 Book (8)
      • 🔎 오브젝트 (4)
      • 🧪 TDD (2)
      • 📜 논문 (2)
    • 🔐 보안 (7)
      • 👾 Pwnable (7)
    • 📝 회고 (4)
    • 🧩 etc. (10)
      • ⚠️ issue (2)
      • 💡 꿀팁 (7)
      • ✏️ 끄적 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 글

hELLO · Designed By 정상우.
jujuwon

시크릿주주

Kotlin :: Backing fields 란
🔠 프로그래밍언어/🍠 Kotlin

Kotlin :: Backing fields 란

2023. 10. 4. 00:56
반응형

코틀린을 공부하면서 계속 어색했던 부분은 프로퍼티(property), Backing fields 라는 표현이었다.

자바에서 접하던 필드, getter, setter 등을 묶어서 코틀린에서는 프로퍼티라고 부르는데, 애매하게 알고 넘어갔더니 뒤로 갈수록 꼬이게 됐다..

왜 필드처럼 생겨가지고는

먼저 프로퍼티와 custom 접근자에 대해 간단히 알아보고, Backing fields 에 대해 알아보자.

 

Backing fields 가 뭘까

class HttpResponse(val body: String, var headers: Map<String, String>)

간단하게 예시 클래스를 만들어보자. body 와 headers 라는 프로퍼티를 가지고 있는 클래스이다.

코틀린을 찍먹해본 사람이라면 알듯이, 코틀린 컴파일러는 body 프로퍼티에 대해서는 getter 를, headers 프로퍼티에 대해서는 getter, setter 를 생성해준다. 그리고 내부적으로 코틀린은 자바로 치면 클래스 내부의 필드를 사용해서 각각의 속성 값을 저장한다. 자바로 디컴파일해보면 아래와 같이 나오는 것을 볼 수 있다.

public final class HttpResponse {
    @NotNull
    private final String body;
    @NotNull
    private Map headers;

    @NotNull
    public final String getBody() {
      return this.body;
    }

    @NotNull
    public final Map getHeaders() {
      return this.headers;
    }

    public final void setHeaders(@NotNull Map var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.headers = var1;
    }
}
  • 꿀팁💡 IntelliJ 에서 Kotlin 디컴파일 하는 법 : Tools > Kotlin > Show Kotlin Bytecode

이렇게 자바 코드로 확인해보면 body 와 headers 에 대해 필드와 getter, setter 가 알맞게 만들어진 것을 확인할 수 있다.

그럼 이번에는 코틀린에서 제공하는 custom 접근자를 만들어보자.

여기서는 body 가 있는지를 알려주는 hasBody 라는 간단한 getter 를 만들어보았다.

class HttpResponse(val body: String, var headers: Map<String, String>) {
  val hasBody: Boolean
      get() = body.isNotBlank()
}

자바로 디컴파일해보면 아래처럼 메소드가 하나 만들어진 게 보인다.

public final boolean getHasBody() {
    CharSequence var1 = (CharSequence)this.body;
    return !StringsKt.isBlank(var1);
}

그런데, 아무리 찾아봐도 hasBody 라는 필드는 보이지 않는다. hasBody 라는 프로퍼티는 body 프로퍼티에서 계산해낼 수 있기 때문에 필드를 만들지 않은 것이다. 그렇다면 이번엔 statusCode 라는 프로퍼티를 만들어보자. 주어진 값이 100~599 사이인 경우에만 statusCode 프로퍼티 값을 설정하도록 custom setter 를 만들었다.

var statusCode: Int = 100
        set(value) {
            if (value in 100..599) statusCode = value
        }

자 custom setter 를 잘(?) 만들었으니 또다시 자바로 디컴파일해보자.

private int statusCode;
...
public final void setStatusCode(int value) {
    if (100 <= value) {
        if (599 >= value) {
          this.setStatusCode(value);
        }
    }
}

이제 문제점이 눈에 보인다 🫠 statusCode 프로퍼티에 값을 set 할 때 custom setter 를 호출하고, setter 안에서 다시 setter 를 호출하는,, 무한 재귀에 빠지게 된다.

물론 IntelliJ 가 warning 띄워줌

이런 무한 재귀를 피하기 위해서는 코틀린이 프로퍼티에 대해 만들어낸 필드 즉, Backing fields를 사용해야 한다.

Backing fields 란 프로퍼티의 값이 저장되는 곳, 자바로 치면 클래스 내의 필드이다.

위 자바 바이트 코드에서 보이듯이 private int statusCode; 이게 바로 Backing fields.

var statusCode: Int = 100
    set(value) {
        if (value in 100..599) field = value
    }

위 코드처럼 field 식별자를 이용하면 custom 접근자 내부의 field 를 참조할 수 있다. 이렇게 field 식별자를 통해서 Backing field 를 참조하면 무한재귀 set 을 막을 수 있다. 아래 자바 바이트코드에서도 우리가 예상한대로 statusCode 필드에 값이 잘 들어가는 것을 확인할 수 있다.

public final void setStatusCode(int value) {
    if (100 <= value) {
        if (599 >= value) {
          this.statusCode = value;
        }
    }
}

 

그럼 Backing fields 는 언제 생길까

코틀린은 하나 이상의 default 접근자를 사용하거나, custom 접근자 안에서 field 식별자를 참조하는 경우 Backing fields 를 만든다.

💡 default 접근자 : val 이나 var 키워드로 생성된 접근자

다시 한번 위 코드에 대한 자바 바이트코드에서 Backing field 로 어떤 것들이 생겨났는지 살펴보자.

public final class HttpResponse {
    private int statusCode;
    @NotNull
    private final String body;
    @NotNull
    private Map headers;
    ...
}
  • body 프로퍼티는 default 접근자에 의해서 backing field 가 생겨났다.
  • headers 프로퍼티도 동일
  • statusCode 프로퍼티는 field 식별자를 참조해서 생겨났다.
  • hasBody 프로퍼티는 default 접근자를 사용하지도, field 식별자를 참조하지도 않기 때문에 backing field 가 생겨나지 않았다

끝.

 

레퍼런스

  • Kotlin In Action
  • https://www.baeldung.com/kotlin/backing-fields
728x90
반응형
저작자표시 (새창열림)
    jujuwon
    jujuwon

    티스토리툴바