기본적으로는 널이 불가능하지만 ?를 붙이면 Nullable 타입이 되어서 널을 대입하고 출력할 수 있다.
세이프 콜이란 null이 할당되어 있을 가능성이 있는 변수를 검사하여 안전하게 호출하도록 도와주는 연산자로, 사용할 변수 이름 뒤에 ?.를 작성하면 된다.
non-null 단정 기호는 null이 아님을 단정하므로 컴파일러가 null검사 없이 무시한다. 따라서 null이 할당되어 있을지라도 컴파일은 잘 진행되지만 실행 중에는 NPE를 발생시킬 수 있기 때문에, 되도록이면 사용하지 않는것이 좋다. 반드시 널이 아니라는 게 보장될 때에만 사용하자!
null을 허용한 변수를 조금 더 안전하고 간단하게 사용하려면 세이프 콜 ?.와 엘비스(Elvis) 연산자 ?:를 함께 사용하면 된다. 엘비스 연산자는 변수가 null인지 아닌지 검사하여 null이 아니라면 왼쪽의 식을 그대로 실행하고 null이라면 오른쪽의 식을 실행한다.
위의 예제에서 a는 기본형으로 Stack에 할당된다. 하지만 ?가 붙은 Nullable 변수 b는 내부적으로 객체여서 동적 공간인 Heap에 할당된다. 즉, b에는 128이라는 값을 가리키는 주소가 저장되어 있다. 그래서 a와 b는 값(==)이 일치(true)하지만 참조 주소(===)는 다르다(false)!
🚨 자바에서는 == 연산자가 값과 참조를 모두 비교한다! 코틀린과의 차이점에 유의하자!
📌 단축키 꿀팁
- 실행 (설정): Alt + Shift + F10
- 현재 파일 실행: Shift + F10
- 줄 간 복사: Ctrl + D
- 다중 선택: Alt + Shift + 더블 클릭
- 새 파일 추가: Alt + Insert
- 추론 타입 확인: Ctrl + Shift + p
a와 b는 모두 기본형으로 Stack에 할당되며, 그 값과 참조가 모두 동일하다.
하지만, Nullable 타입의 c와 d는 내부적으로 '객체'여서 그 값이 동적 공간인 Heap에 할당된다. 그리고 c와 d는 Stack의 서로 다른 주소 공간에 할당되어 힙에 있는 객체를 가리킨다. 따라서 두 변수의 주소는 다르다!
단, 여기서 하나 더 알아야 할 점이 있는데 코틀린에서 참조형으로 선언한 변수의 값이 -128~127 범위에 있으면, 힙에 따로 객체를 생성하지 않고 캐시에 값을 저장하기 때문에 주소가 동일하게 나올 수 있다는 것이다! 실제로 확인해보자!
아까는 c === d 연산의 결과가 false 였는데, 값의 크기를 줄이니까 true로 나왔다!
Ctrl + Shift + p 를 눌러서 타입을 확인해보면 실제로 스마트 캐스트가 되었다는 걸 확인할 수 있다!