안드로이드 개발자의 창고
[17일차 Kotlin] Casting(캐스팅) 본문
📖 캐스팅(형변환)
- 변수에 담긴 값이나 객체를 다른 형태로 변환하는 것을 의미한다.
- Kotlin은 모든 값을 객체로 관리하기 때문에 Kotlin에서의 형변환은 다른 클래스 타입의 객체로 변환하는 것을 의미한다.
- 자식 클래스 타입으로의 변환
- 부모 클래스 타입으로의 변환
- 다른 자료형 타입으로의 변환
- null 허용과 null 불허용 간의 변환
스마트 캐스팅(Smart Casting)
- 특정 조건을 만족하면 자동으로 형변환이 발생하는 개념이다.
- 스마트 캐스팅 기능 덕분에 형변환에 대해 개발자가 크게 신경을 쓰지 않아도 된다.
- 형 변환은 객체의 클래스 타입이 아닌 객체의 주소 값을 가지고 있는 참조 변수의 타입이 변경되는 것이다.
객체 타입 변환
- 객체의 타입 변환은 상속관계나 구현한 인터페이스 타입에 해당한다.
- 부모 클래스 타입으로의 형 변환
- 자식 클래스 타입으로의 형 변환
- 구현한 인터페이스 타입으로의 형 변환
- 인터페이스를 구현한 클래스 타입으로의 형 변환
as 연산자
- 객체를 지정된 클래스 타입으로 변환하는 연산자이다.
- 참조변수 as 클래스타입
- 만약 객체가 지정된 클래스타입과 관계가 없을 경우 오류가 발생한다.
- 형 변환이 발생한 참조 변수는 변환된 타입을 유지한다.
is 연산자
- 형 변환이 가능하면 변환을 하고 true를 반환한다.
- if 문으로 구성하여 사용하며 if 문 내에서만 변환된 타입을 사용하고 if 문을 나가게 되면 변환되기 전의 타입으로 다시 변경된다.
Any 타입
- Kotlin은 모든 클래스가 직접 혹은 간접적으로 Any 클래스를 상속받는다.
- 따라서 모든 객체의 주소 값은 Any 타입 참조 변수에 담을 수 있다.
- Any 타입과 is 연산자를 활용하여 다양한 타입의 객체에 대응할 수 있는 코드를 만들 수 있다.
기본 타입의 형변환
- Kotlin 에서는 기본 타입을 관리하는 객체의 타입을 변경하는 메서드를 제공한다.
- 참조 변수의 타입이 변경되는 것이 아닌 새로운 객체가 생성되어 반환된다.
- toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar()
📖 예제 코드
open class SuperClass1
interface Inter1
class SubClass1 : SuperClass1(){
fun subMethod1(){
println("SubClass1의 subMethod1입니다.")
}
}
class SubClass2 : Inter1{
fun subMethod2(){
println("SubClass2의 subMethod2입니다.")
}
}
class SubClass3
fun main() {
val obj1:SubClass1 = SubClass1()
val obj2:SubClass2 = SubClass2()
val obj3:SuperClass1 = obj1
val obj4:Inter1 = obj2
println("obj3 : $obj3")
println("obj4 : $obj4")
obj3.subMethod1() <<< 오류 발생
obj4.subMethod2() <<< 오류 발생
obj3 as SubClass1
obj3.subMethod1() // SubClass1의 subMethod1입니다.
obj4 as SubClass2
obj4.subMethod2() // SubClass2의 subMethod2입니다.
val temp2:SubClass3 = SubClass3()
temp2 as SuperClass1 <<< 오류 발생
temp2 as Inter1 <<< 오류 발생
val obj5:SubClass1 = SubClass1()
val temp3:SuperClass1 = obj5
val temp4 = obj5 as SuperClass1
println("temp3 : $temp3") // SubClass1@ ~~~
println("temp4 : $temp4") // SubClass1@ ~~~
val chk1 = temp4 is SubClass1
val chk2 = temp4 is SuperClass1
val chk3 = temp4 is Inter1
println("chk1 : $chk1") // true
println("chk2 : $chk2") // true
println("chk3 : $chk3") // false
}
✔️ 코드 해석
- obj3.subMethod1() / obj4.subMethod2()
- 객체에 접근할 때 부모 클래스 혹은 구현한 인터페이스 타입으로 접근하면 자식 클래스에 있는 메서드 중 overriding한 것이 아닌 것은 호출할 수 없다.
- obj3 as SubClass1 / obj4 as SubClass2
- 부모클래스 타입형 변수에 담긴 객체를 자식 클래스 형으로 변환한다.
- as : 변수의 타입을 다른 클래스 타입으로 변환하는 연산자
- 상속 관계에 있거나 구현한 인터페이스 관계가 있을 경우에만 성공한다.
- 스마트 캐스팅에 해당되지 않는다.
- temp2 as SuperClass1 / temp2 as Inter1
- 상속관계나 인터페이스 구현 관계가 아닌 객체의 형변환
- 전혀 관계가 없다고 하더라도 문법적으로 오류가 발생하지는 않는다.
- 실행 중에 오류가 발생한다.
- val temp3:SuperClass1 = obj5
- 객체를 담을 변수에 타입을 설정하면 형변환이 자동으로 이루어진다.
- val temp4 = obj5 as SuperClass1
- 객체를 담을 변수에 타입을 설정하지 않으면 변수의 타입은 객체의 클래스 타입으로 결정된다.
- 이럴 때는 as 이용해 형변환해주면 형변환된 클래스타입 변수로 정의된다.
- val chk1 = temp4 is SubClass1 / val chk2 = temp4 is SuperClass1 / val chk3 = temp4 is Inter1
- 참조변수를 통해 접근할 수 있는 객체에 해당 클래스 영역이 있는지 검사한다.
fun main(){
// 스마트 캐스팅
val super3:SuperClass1 = SubClass1()
if(super3 is SubClass1){
super3.subMethod1()
}
super3.subMethod1() <<< 오류 발생
val obj10 = SubClass1()
val obj11 = SubClass2()
val obj12 = 100
val obj13 = "문자열"
anyMethod(obj10)
anyMethod(obj11)
anyMethod(obj12)
anyMethod(obj13)
}
fun anyMethod(obj:Any){
if(obj is SubClass1){
obj.subMethod1()
}
if(obj is SubClass2){
obj.subMethod2()
}
if(obj is Int){
println("정수입니다")
}
if(obj is String){
println("문자열 입니다")
}
}
✔️ 코드 해석
- val super3:SuperClass1 = SubClass1()
- 참조변수(super3)를 통해 접근할 수 있는 객체에 원하는 클래스의 영역(SubClass1)이 있는 경우 자동으로 형변환을 해준다.
- if문 밖에 있는 super3.subMethod1()
- if 문 밖으로 나가면 형변환 되지 않은 상태가 된다.
- SuperClass1에서는 SubClass1의 메서드에 접근할 수 없기 때문에 오류가 발생한다.
- fun anyMethod(obj:Any){ ... }
- 스마트 캐스팅과 Any를 이용하면 하나의 메서드로 여러 클래스타입의 객체에 대한 작업을 수행할 수 있다.
- obj10은 subMethod1()을 호출한다.
- obj11은 subMethod2()를 호출한다.
- obj12는 "정수입니다"를 출력한다.
- obj13은 "문자열 입니다"를 출력한다.
fun main(){
val number1:Int = 100
val number2:Long = number1.toLong()
println("number2 : $number2")
val str1:String = "100"
val number3:Int = str1.toInt()
println("number3 : $number3")
val str2:String = "안녕하세요"
val number4:Int = str2.toInt() <<< 오류 발생
println("number4 : $number4")
}
✔️ 코드 해석
- val number2:Long = number1.toLong()
- 더 큰 자료형에 값을 저장한다.
- Int는 4bute, Long은 8byte
- val number4:Int = str2.toInt()
- 문자열이 숫자로만 구성된 것이 아니기 때문에 숫자로 변환시 오류가 발생한다.
'Computer > Kotlin' 카테고리의 다른 글
[17일차 kotlin] 열거형 클래스(Enum Class) (0) | 2023.05.20 |
---|---|
[17일차 Kotlin] Null 안전성을 위한 형변환(Null Casting) (0) | 2023.05.20 |
[16일차 Kotlin] Null 처리(!! 연산자, ?: 연산자, ?. 연산자) (0) | 2023.05.20 |
[16일차 Kotlin] 중첩 클래스 (0) | 2023.05.19 |
[16일차 Kotlin] Generic (0) | 2023.05.18 |