Kotlin

[Kotlin] TypeCasting

hvoon 2022. 9. 14. 15:51

기본 자료형 클래스 간의 형변환

fun main() {
    var a1:Int = 100
    //var a2:Double = a1 -> error
    var a2:Double = a1.toDouble()

    var b1:Double = 123.12
    // var b2:Int = b1
    var b2:Int = b1.toInt()

    var c1:String = "12234"
    var c2:Int = c1.toInt()

    var d1:String = "122.34"
    var d2:Double = d1.toDouble()

    // val d3:String = "안녕하세요"; val number4:Int = d3.toInt() -> error
}

 

fun main() {
// 1. 부모 클래스 참조변수에 자식 클래스의 인스턴스를 저장
    // 스마트 캐스팅 발생
    val super1:SuperClass4 = SubClass41() // SuperClass: 부모클래스, SubClass41:자식
    // 스마트 캐스팅 발생
    val inter1:Inter4 = SubClass42() //  Inter4: 부모인터페이스, SubClass42: 자식클래스


// 2. 자식 인스턴스가 부모래퍼런스 변수에 저장되었다가 다시 자식래퍼런스변수로 옮겨 저장될 때,
//    강제캐스팅이 필요하다는건 자바나 코틀린이나 같음.
//    옮겨지는 인스턴스는 반드시 자식인스턴스여야하는 제약과 똑같음. 
//    다만 코틀린과 자바의 명령이 달라짐.

    // 자바 문법
    // val sub1:SubClass41 = (SubClass41)super1
    // val sub2:SubClass42 = (SubClass42)inter1

    // 코틀린에서 자식인스턴스를 담고 있는 부모래퍼런스 변수값이 자식래퍼런스 변수로 이동할 때
    super1 as SubClass41    // 자바의 super1 = (SubClass41)super1 명령과 같음
    inter1 as SubClass42    // 자바의 inter1 = (SubClass42)inter1 명령과 같음
    // 위 명령은 super1과 inter1에 있는 레퍼런스 값을 옮기려는 자식 클래스 자료형의
    // '다른 변수에 형변환 과 함께 옮기는 것이 아니라' 해당 자료형으로 변경시켜버림.
    // 이 명령 이후 super1 변수의 자료형은 SubClass41이 되고 
    // inter1 변수의 자료형은 SubClass42가 됨
    // '새로운 자식 클래스 레퍼런스 변수'로 값을 옮겨 담는 것이 아니라, 저장된 참조값을 놔두고
    // '현재 변수의 자료형을 변경'해 버린다는 뜻
    println("변경 후 super1 : $super1")
    println("변경 후 inter1 : $inter1")
    // 형변환의 유효영역은 as 명령을 감싸고 있는 중괄호 안쪽임

    // 자바의 경우 위 두개의 경우 형변환전에 안전한 실행을 위해 점검을 했음
    // if( super1 instanceof SubClass41 ) {
    //      val sub1:SubClass41 = (SubClass41)super1  //형변환 명령
    //  }
    // 코틀린에서는
    // if( super1 is SubClass41 ){
    //    super1 as SubClass41 // 코틀린 강제 형변환 명령
    // }

    // 먼저 자식 인스턴스를 부모레퍼런스에 저장
    val super2:SuperClass4 = SubClass41()
    val inter2:Inter4 = SubClass42()

    // 다시 부모레퍼런스가 저장하고 있는 자식인스턴스를 자식 레퍼런스에 옮길텐데,
    // 위에서 언급한거 처럼 코틀린은 옮기지않고, 레퍼런스 변수 자체를 변경해버립니다
    // 그전에 변경이 가능하지 검사
    if( super2 is SubClass41 ){
        super2 as SubClass41  // if문의 중괄호 밖에서도 형변환 결과를 활용할수 있습니다.
    } else {
        println("형변환이 불가능합니다.")
    } // 검사결과가 참이면 변환, 거짓이면 변환하지 않음


    if( inter2 is SubClass42 ){
        // is 에 의해 열린 if 문 안에서는  as 를 쓰지 않아도
        // is 연산자 값이 true라면 형변환이 가능한 상황이므로 자동으로 스마트 캐스팅 실행됨
        // 현재위치 중괄호 { } 안에는 이미  inter2 는 SubClass42의 레퍼런스로 변경된 상태이며 
        // 그 상태로 사용이 가능
        // 다만  중괄호를 벗어나면  다시  Inter4(부모인터페이스)의 레퍼런스로 되돌아감
        // 중괄호가 끝나도 계속 변경 상태를 유지하려면 inter4 as SubClass42를 사용함
    }

}
open class SuperClass4
interface Inter4

class SubClass41 : SuperClass4(){
    fun subMethod1(){
        println("SubClass21의 subMethod1입니다")
    }
}
class SubClass42 : Inter4{
    fun subMethod2(){
        println("SubClass21의 subMethod2입니다")
    }
}