Kotlin 공식 문서 살펴보기 (6) - 타입 확인과 캐스트

is & !is 연산자

  • 객체가 주어진 타입과 맞는지 여부를 확인하는 런타임 검사
if (obj is String) {
    print(obj.length)
}

if (obj !is String) {
    print("not a stirng")
} else {
    print(obj.length)
}

스마트 캐스트

  • 대부분의 경우 명확한 캐스트 연산자를 사용할 필요가 없음
  • 컴파일러가 is 확인을 트래킹하고 값을 변경할 수 없는 객체에 명시적 캐스트를 하고 필요할 경우 자동으로 안전한 캐스트를 함
fun demo(x: Any) {
    if (x is String) {
        print(x.length)  // x는 자동으로 문자열로 캐스팅됨
    }
}
  • 컴파일러는 부정 확인이 return으로 끝날 경우, 캐스트가 안전한 것을 알 수 있음
if (x !is String) return

print(x.length) // x는 자동으로 문자열로 캐스팅됨
  • 또는 캐스팅이 &&, ||의 오른쪽에 있고 타입 확인이 왼쪽에 있을 때도 동일
// x는 ||의 오른편에서 자동으로 문자열로 캐스팅됨
if (x !is Strijng || x.length == 0) return

// x는 &&의 오른편에ㅓ 자동으로 문자열로 캐스팅됨
if (x is String && x.length > 0) {
    print(x.length)
}
  • 스마트 캐스트는 when 표현식과 while 루프에서도 동작
when (x) {
    is Int -> print(x + 1)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
}
  • 스마트 캐스트는 변수가 확인과 사용법이 바뀌지 않을 것을 컴파일러가 보증할 때만 동작

안전하지 않은 캐스트 연산자

  • 보통 캐스팅 할 수 없으면 예외가 발생하며 이를 안전하지 않다(unsafe)고 함
  • 안전하지 않은 캐스트는 as로 수행
val x: String = y as String
  • null은 문자열로 캐스트될 수 없고 만약 위에서 y가 null이면 예외 발생
  • null값을 위해 위의 예제를 바꾸려면 캐스트 오른쪽에 null 타입을 추가
val x: String? = y as String?

안전한 nullable 캐스트 연산자

  • 예외를 방지하기 위해 실패할 때 null을 반환하는 안전한 캐스트 오퍼레이터인 as?를 사용
val x: String? = y as? String
  • as?의 오른쪽이 nullable하지 않은 문자열이어도 캐스트의 결과는 nullable 함

타입 삭제와 제네릭 타입 확인

  • 코틀린은 컴파일 시간에 제네릭 관련 작업에 타입 안정성 보장
  • 런타임에서는 제네릭 타입의 인스턴스는 실제 타입 인자에 대한 정보를 가지고 있지 않음
  • 런타임에서는 타입 삭제 때문에 컴파일러는 제네릭 타입은 is 확인을 금지
  • * 이용한 인스턴스 확인은 가능
if (something is List<*>) {
    something.forEach( println(it) )
}
  • 컴파일 시간에 정적 인스턴스 타입 검사가 이루어진 경우에는 is 확인과 제네릭이 아닌 부분을 포함하는 캐스트 가능
fun handleStrings(list: List<String>) {
    if (list is ArrayList) {
        // list 는 ArrayList<String> 으로 스마트 캐스트 됨
    }
}

확인되지 않은 캐스트

  • 확인되지 않은 캐스트를 방지할 수 있는 방법
    • 추상화
    • reified 타입 파라미터
    • @Superclass("UNCHECKED_CAST") 어노테이션