lateinit 키워드 관련해서 질문드립니다!
안녕하세요! 수업 듣다가 급혼란(?)이 찾아와서 질문을 드리려고 합니다!
lateinit 키워드는 primitive 타입에서는 사용할 수 없는 이유가 컴파일 되었을 때 null을 저장할 수 없어서 라고 설명을 해주셨는데요.
그러다보니 lateinit var name: String 이 코드에 대해서 갑자기 혼란이 찾아왔습니다. String? 이 아니기 때문에 name에도 null은 들어갈 수 없는 것은 확정적인데, 이러면 Int, Long 이런 것과 뭐가 다른가 하는 순간적인 혼란이 찾아오네요.
코틀린에서의 String을 바이트 코드 디컴파일하면 어차피 자바 String이 되기 때문에 자바에서의 String은 null이 될 수 있기 때문에 코틀린에서 String은 String?이 아니어도 바로 lateinit을 사용할 수 있게 되는가 하는 생각도 해봤는데 이게 맞는지는 모르겠네요..ㅠ
뭔가 되게 간단한 것 같은데 헷갈려서 질문을 드려서 죄송하네요 ㅠ
Answer 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에만 적용될 수 있다.
이해에 도움이 되셨으면 좋겠습니다. 감사합니다!!! 🙇🙇
싱글턴패턴
0
1
1
KType 관련 Kotlin 2.3 변경점
1
61
2
Kotlin 2.0(K2 컴파일러)에서 달라진 Java SAM 변환 동작
2
98
3
SuperTypeSafeCage에 대해 질문드립니다
0
62
2
좋은 코드 예시
0
94
2
val 키워드도 setValue가 있나요?
0
86
2
반공변성 질문드립니다.
1
114
3
[23강] SuperTypeToken의 equals 관련 질문
1
96
2
23강 타입 안전 이종 컨테이너 예제 관련 문의 드립니다.
0
111
2
abstract class Fish(name:String):Animal(name)
0
105
2
지식공유자님 inline에 대해서의 질문과 추가적인 질문 1가지가 있습니다!
1
118
1
안녕하세요 JMH 설정 관련 팁을 드릴까 합니다! (24년 12월 16일 기준)
0
164
2
Generic Func 질문이 있습니다
1
104
1
2강부터 영상 재생이 안되네요ㅠㅠ
0
152
2
by lazy 블럭 안에서 suspend 함수의 결과값을 받는게 가능한가요?
0
389
1
DSL 만들기
0
288
1
Sequence vs Stream
1
251
1
코틀린 indent 코드 스타일 질문입니다.
0
263
1
non-local return 질문입니다.
1
227
1
SynchronizedLazyImpl 함수관련 질문
0
424
2
제네릭 클래스를 정의하는 경우, 반드시 변성을 고려하는 것이 바람직한가요?
4
1327
1
실무에서 lateinit 이 필요한 경우는 어떤 상황일까요?
1
455
1
4강 타입소거 관련 질문
1
331
2
추상클래스의 공변 / 반공변, 추상 제네릭 일급컬랙션 리팩토링 에 대한 질문입니다.
2
598
1

