Kotlin - 캐스팅

이동수·2024년 9월 9일

Kotlin

목록 보기
18/33
post-thumbnail

var a: Drink = Cola() //드링크 기능만 사용, 업케스팅
var b: Cola = Cola() //콜라 기능도 사용가능

업 케스팅(up casting) - 콜라 인스턴스를 음료 변수에 담는 행위(상위 자료형인 수퍼클래스로 변환한다)
다운 케스팅(down casting) - 하위 자료형으로 변환

업 케스팅 - var a: Drink = Cola() 처럼 간단하게 됨
다운 케스팅 - as, is필요함

Type Check (is)

런타임에 특정 인스턴스 또는 변수의 형식(data type) 또는 클래스를 확인해 다른 개체에 대한 흐름을 분리하는 방법

if(A is B)가 참이면 자동으로 캐스팅됨.

ex1)

any - 인간 - 남자(수염이난다) - 표인수(강의한다)

………………..- 여자(수유한다) - 서윤지(강의를 듣는다)

fun d(: 서윤지){.직립보행하다
}

서윤지는 - 서윤지, 여자, 인간, any 를 가지고있다

여기서 인간 as 남자 (되는데 불가능, 서윤지에 남자가 없음)

ex2)

fun e(: 서윤지){
	if(인간 is 서윤지)
}

if(인간 is 서윤지)가 참이되면 자동으로 casting해줌 - down casting (smart casting)

그러나 if(인간 !is 서윤지)가 참이면 인간이 서윤지가 아니므로 아무일도 안일어남

  • 만약 else까지 있으면 else는 참이 되므로 else에서 스마트캐스팅이 일어남

ex3)

shape - circle

…..…… - squre - rectangle

val shapeObject: Shape = Circle() // shapeObject는 3개의 RTTI정보가 있다(circle, shape, any)
    val message = if (shapeObject is Circle) { //참이면 circle로 smart casting 아니면 다음으로
        "Circle Instance"
    } else if (shapeObject is Square) {
        "Square Instance"
    } else if (shapeObject is Rectangle) {
        "Rectangle Instance"
    } else {
        "Nothing"
    }
    print(message)
  • shapeObject: Shape = Circle()이 rectangle이면 "Square Instance" 출력
    • rectangle에 square가 있기때문 (rectangle → any, shape,squre, rectangle가짐)
  • squre is rectangle은 안됨. squre에 rectangle이 없으니

최종

A is BA가 B를 가지고 있느냐?

ex) Square is Rectangle → Squre은 any,shape,square만 있다. rectangle이 없다. 거짓임.

Type Casting (as)

  • 클래스에서 생성된 instance에서 명시적으로 casting할때 사용 (명시적으로 해당 타입을 변경할때)
    var shapeObject = Circle()
    
    var otherShapeObject = shapeObject as Circle
    var nullableShapeObject : Circle? = shapeObject as Circle?
    var safeCastObject : Circle? = shapeObject as? Circle
    • 첫번째 줄에 Circle()말고 Rectangle()을 넣으면 compile error는 안뜨는데 ClassCastException발생
      • ANR발생하여 프로그램이 멈춤

ANR (Application Not Responding) : APP이 응답하지 않는 오류. 수백개가 있음, 앱멈춤, 액티비티가 5초안에 보여지지않으면 발생함

최종 예시 (꼭 확인하자)

fun main(){
    var a = Drink()
    a.drink()               //음료 을 마십니다.

    var b: Drink = Cola()   //Drink타입의 변수 b를 할당
                            //아 타입할당을 class로 할수 있는건가보다
    b.drink()               //음료 중에 콜라 를 마십니다
                            //그러나 b는 Drink변수입으로 washDishes()함수 실행을 못한다

    if(b is Cola){          //다운 케스팅, b가 콜라와 호환되는지 여부확인 후 다운함
        b.washDishes()      //조건문 안에서만 다운 케스팅됨
    }                       //콜라로 설거지를 합니다

    // b.washDishes() 오류  //is는 조건문 안에서만 다운 케스팅되니까
    var c = b as Cola
    c.washDishes()          //콜라로 설거지를 합니다
    b.washDishes()          //콜라로 설거지를 합니다
}
open class Drink{
    var name = "음료"

    open fun drink(){
        println("$name 을 마십니다.")
    }
}
class Cola: Drink(){
    var type = "콜라"

    override fun drink() {
        println("$name 중에 $type 를 마십니다")
    }
    fun washDishes(){
        println("${type}로 설거지를 합니다")
    }
}
  • var b: Drink = Cola() 에서 b는 drink변수이므로 Cola의 washDishes는 사용하지 못한다. (중복되는 변수, 함수는 cola꺼로 적용됨)
  • is는 조건문 안에서만 다운 케스팅된다.

번외

primitive type casting

val intData: Int = 123
val floatData: Float = intData.toFloat()
val foo = 345.toDouble()

RTTI

  • runtime type information(inovacation)

0개의 댓글