해결된 질문
작성
·
252
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에만 적용될 수 있다.
이해에 도움이 되셨으면 좋겠습니다. 감사합니다!!! 🙇🙇
이해가 잘 되었습니다! 감사합니다 :) 정말 친절하세요ㅠㅠ