• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

lateinit 키워드 관련해서 질문드립니다!

23.09.22 17:03 작성 조회수 211

1

안녕하세요! 수업 듣다가 급혼란(?)이 찾아와서 질문을 드리려고 합니다!

lateinit 키워드는 primitive 타입에서는 사용할 수 없는 이유가 컴파일 되었을 때 null을 저장할 수 없어서 라고 설명을 해주셨는데요.

그러다보니 lateinit var name: String 이 코드에 대해서 갑자기 혼란이 찾아왔습니다. String? 이 아니기 때문에 name에도 null은 들어갈 수 없는 것은 확정적인데, 이러면 Int, Long 이런 것과 뭐가 다른가 하는 순간적인 혼란이 찾아오네요.

코틀린에서의 String을 바이트 코드 디컴파일하면 어차피 자바 String이 되기 때문에 자바에서의 String은 null이 될 수 있기 때문에 코틀린에서 String은 String?이 아니어도 바로 lateinit을 사용할 수 있게 되는가 하는 생각도 해봤는데 이게 맞는지는 모르겠네요..ㅠ

뭔가 되게 간단한 것 같은데 헷갈려서 질문을 드려서 죄송하네요 ㅠ

답변 1

답변을 작성해보세요.

1

안녕하세요, JUNN님! 아이고 이 부분이 엄청 헷갈리죠!!

좋은 질문 감사드려요~~ (언제나 편하게 질문 주셔도 괜찮습니다) 😊

 

한 번 차근차근 설명 드려 보겠습니다.

 

[1. String은 무슨 타입인가]

JVM에서 String은 reference type 입니다!

물론 String 타입을 어떻게 선언하는지에 따라 메모리 저장 위치가 JVM 버전에 따라 달라질 수 있지만 (https://medium.com/@joongwon/string-%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0-57af94cbb6bc 를 보시면 좋습니다!) 아무튼 String은 reference type입니다!

때문에 JVM의 String에는 "null"이 들어갈 수 있죠!

 

반면, JVM의 int나 long은 (i와 l이 소문자입니다!) primitive type입니다. 때문에 null이 들어갈 수 없죠!

이것이 String과 int, long의 큰 차이점입니다.

 

[2. Kotlin의 Int와 Long]

그럼 이제 JVM에서 Kotlin으로 넘어와 보겠습니다.

 

강의에서 설명드렸던 것처럼 lateinit 이라는 키워드가 어떠한 필드 앞에 붙게 되면, Kotlin은 컴파일 과정에서 해당 필드를 다음과 같이 컴파일 합니다.

// Kotlin
lateinit var data: Data // Data 타입

// 컴파일된 코드 (Java 느낌)
// Java 코드이기 때문에 여기는 Data와 null이 들어갈 수 있습니다. <--- 핵심
public Data data; 

// 하지만 getter 에서 null check를 해주기 때문에 절대 null이 아니죠
public Data getData() { 
  if (this.data == null) {
    throw UninitializedPropertyAccessException()
  }
  return data;
}

 

어떤 느낌인지 감이 오시죠?!!

자 그럼 이제 Data를 String이라고 생각해봅시다! 🙂

 

Kotlin의 String 혹은 String?은 모두 JVM의 String 타입으로 변환됩니다. 그리고 JVM String 타입은 null이 들어갈 수 있죠! 따라서 Data 자리에 String이 들어가더라도 null이 JVM String 타입 필드에 들어갈 수 있으므로 문제가 없습니다.

 

 

자 그런데 Kotlin의 Int는 JVM의 int로 Int?는 Integer로 변환됩니다. 때문에 만약 lateinit var num: Int 와 같이 코드를 작성하게 되면 위의 규칙에 따라 아래와 같이 컴파일 되어야 합니다.

// 컴파일된 코드 (Java 느낌)
public int data; 

public Data getData() { 
  if (this.data == null) { // ????? 이상하다!!
    throw UninitializedPropertyAccessException()
  }
  return data;
}

여기서 이상한 점이 생깁니다. data는 int라서 null check 자체를 할 수가 없습니다!!!

그렇기 때문에 lateinit var num: Int 는 사용할 수가 없습니다.

 

그렇다면 lateinit var num: Int? 로 작성할 경우 JVM Integer 타입이 들어갈 거고 이 필드는 null check를 하거나 null 값을 넣을 수 있으니 괜찮겠네요?! 라고 생각하실 수도 있는데요!

이 경우는 어차피 lateinit의 목적이 Kotlin 타입 관점에서 nullable을 제거하는 것이기 때문에 사용 가치가 없게 됩니다 😭

 

 

이를 두 줄 요약 드려보면 다음과 같습니다.

  • 코틀린 관점에서 String은 reference type이고 Int는 primitive type이다.

  • lateinit은 reference type에만 적용될 수 있다.

 

이해에 도움이 되셨으면 좋겠습니다. 감사합니다!!! 🙇🙇

이해가 잘 되었습니다! 감사합니다 :) 정말 친절하세요ㅠㅠ