본문 바로가기
Kotlin/Kotlin 프로그래밍

[Kotlin] 변수와 자료형, 연산자 (2)

by 주 녕 2021. 4. 2.
728x90

모든 내용은 Do it! 코틀린 프로그래밍을 바탕으로 정리한 것입니다. 

 

자료형 검사하고 변환하기

코틀린은 변수를 사용할 때 반드시 값이 할당되어 있어야 한다는 원칙이 있음

fun main() {
//	var str1: String = "Hello Kotlin" -> 오류
	var str1: String? = "Hello Kotlin"
	str1 = null
	println("str1: $str1")
}

→ 변수의 null 허용 여부에 따라 String(허용X)과 String?(허용O)은 서로 다른 자료형

 ? : 변수에 null을 할당하기 위한 기호

 

세이프 콜과 non-null 단정 기호

fun main() {
	var str1: String? = "Hello Kotlin"
	str1 = null
	println("str1: $str1, length: ${str1.length}") // null을 허용하면 length가 실행X
}

→ String?형에서는 세이프 콜(?.)이나 non-null 단정 기호(!!.)만 허용함

  • 세이프 콜
    • null이 할당되어 있을 가능성이 있는 변수를 검사하여 안전하게 호출하도록 도와주는 기법
    • 호출할 변수 이름 뒤에 ?. 를 작성 (${str1?.length})
    • null일 때는 null을 출력하게 됨
  • non-null 단정 기호
    • 변수에 할당된 값이 null이 아님을 단정하므로 컴파일러가 null 검사 없이 무시함
    • 호출할 변수 이름 뒤에 !!. 를 작성 (${str1!!.length})
    • 따라서 변수에 null이 할당되어 있어도 컴파일러는 진행, but NPE 발생

 

세이프 콜과 엘비스 연산자를 활용해 null 허용 변수 안전하게 사용하기

fun main() {
	var str1: String? = "Hello Kotlin"
	str1 = null
	// if(str1 != null) str1.length else -1
	println("str1: $str1, length: ${str1?.length ?: -1}")
}

→ null을 허용한 변수를 안전하게 사용하기 위해서는 세이프콜과 엘비스 연산자(?:)를 함께 사용하면 됨

  • 엘비스 연산자
    • 변수가 null인지 아닌지 검사하여 null이 아니라면 왼쪽 식을 실행하고 null이라면 오른쪽 식을 실행함
    • null인 경우 반환값을 특정 값으로 대체함
    • null 발생에 대비할 수 있고, 코드를 한 줄에 표현할 수 있어 가독성↑

 


자료형의 비교, 검사, 변환

코틀린은 서로 다른 자료형을 비교하거나 연산할 수 없음

자료형 변환

  • in 자바 : 자료형이 서로 다르면 자동으로 변환 (자동 형변환)
  • in 코틀린 : 자료형이 다른 변수에 재할당하면 자동 형 변환이 되지 않고 자료형 불일치 오류(Type Mismatch)가 발생

→ toByte(), toLong(), toShore(), toInt(), toFloat(), toDouble(), toChar()

* 표현식에서 자료형이 서로 다른 값을 연산하면 자료형이 표현할 수 있는 범위가 큰 자료형으로 자동 형 변환하여 연산

 

기본형과 잠초형 자료형의 비교 원리

  • 단순한 값의 비교 (==) : 참조에 상관 없이 값이 동일하면 true를, 값이 다르면 false를 반환
  • 참조 주소 비교 (===) : 값과 상관 없이 참조가 동일하면 true를, 참조가 다르면 false를 반환
fun main() {
	val a: Int = 128
	val b = a
	println(a === b)  // true : 자료형이 기본형 int가 되어 값이 동일
    
	val c: Int? = a
	val d: Int? = a
	val e: Int? = c
	println(c == d)  // true : 값만 비교
	println(c === d)  // false : 값은 같지만 참조 주소를 비교했을 때 주소가 다름
	println(c === e)  // true : 값도 같고 참조 주소도 같음
}
  • a, b는 참조형인 Int로 선언되었지만 코틀린 컴파일러에 의해 기본형으로 변환되어 저장
    • 스택에는 주소가 아닌 값 128이 저장됨
    • == , === 에 상관없이 true
  • c, d, e는 null을 허용한 참조형 변수
    • c, d는 a에 들어 있는 값이 아닌 서로 다른 참조 주소가 저장됨 
    • e는 c의 참조 주소가 저장됨 → === 비교 : true 

 

스마트 캐스트

어떤 값이 어떤 형인지 알 수 없을 때 그때마다 자료형을 변환해도 되지만 컴파일러가 자동으로 형 변환을 하는 스마트 캐스트를 사용하는 것이 더 편리함

  • Number형 : 숫자를 저장하기 위한 특수한 자료형 객체
    • 저장되는 값에 따라 Float형, Int형, Long형 등으로 스마트 캐스트 됨

 

자료형 검사하기

is 키워드

fun main() {
	val num = 256
	
    if (num is Int) {
		print(num)
	} else if (num !is Int) {
		print("num is not Int")
	}
}

왼쪽의 변수가 오른쪽의 자료형과 같으면 true, 다르면 false를 반환

fun main() {
	val x: Any
	x = "Hello"
	if (x is String) {
		print(x.length)
	}
}

Any형(코틀린의 최상위 기본 클래스, 특수한 자료형)을 사용하여 자료형을 결정하지 않은 채로 변수를 선언한 경우,

→ 자료형을 검사한 다음 그 변수를 해당 자료형으로 변환함

 

as에 의한 스마트 캐스팅

as 키워드

val x: String = y as String

→ y가 null이 아니면 String으로 형 변환되어 x에 할당

BUT y가 null이라면? 형 변환을 할 수 없어 예외가 발생할 것

 

val x: String? = y as? String

→ null 가능성까지 고려하여 예외 발생을 피하려면 ?를 사용할 것

*as는 형 변환이 가능하지 않으면 예외를 발생시킴

 

묵시적 변환

  • 코틀린의 Any형 : 모든 클래스의 뿌리
    • 코틀린의 모든 클래스는 Any형이라는 슈퍼클래스를 가짐
    • Int나 String, 사용자가 직접 만든 클래스까지 모두 Any형의 자식 클래스
    • 무엇이든 될 수 있기 때문에 필요한 자료형으로 자동 변환할 수 있음

 

728x90

댓글