reifeid
- 일반적으로 제네릭 타입은 런타임 시점에서 사라짐(타입 소거, type erasure)
→ T는 런타임에 어떤 타입인지 알 수 없어서 컴파일 에러fun <T> printType(value: T) { println(T::class) // ❌ 오류! }
→ inline과 reified를 함께 사용하여 T의 실제 타입 정보를 런타임에서도 사용 가능:
⭑Type Erasure글 추가 예정
사용법
inline fun <reified T> printType(value: T) {
println(T::class)
}
- inline: 함수를 호출한 곳에 코드가 인라인으로 삽입(호출 지점에 복사) → 타입 정보 유지 가능
- reified: 제네릭 타입 T를 런타임에서도 사용 가능
사용 이유
- T::class, T::class.java가 필요한 경우
T::class / T::class.java
- T::class
= Kotlin의 클래스 참조
= 반환 타입: KClass<T>
- T::class.java
= Java의 클래스 참조
= 반환 타입: Class<T>
⭑ T::class, T::class.java글 추가 예정
- value is T, value as? T처럼 런타임 타입 체크가 필요한 경우
- Retrofit, Gson, Moshi등의 제네릭 기반 객체 변환, 타입 검사 유틸 함수 등에 자주 사용
예시
inline fun <reified T> isOfType(value: Any): Boolean {
return value is T
}
fum main() {
println(isOfType<String>("hello")) // true
println(isOfType<Int>("hello")) //false
}
reified가 없는 경우 비교
reified 없이 구현한 경우
fun <T: Any> fromJson(json: String, clazz: Class<T>): T{
return Gson().fromJson(json, clazz)
}
val json = """{"name":"희우","age":24}"""
val user = fromJson(json, User::class.java)
- T의 실제 타입을 런타임 과정에서 알 수 없음
→ User::class.java를 반드시 인자로 넘겨야함 - T: Any
- non-null 타입을 명시
- Java 라이브러리와의 연동 시 타입 안정성을 지킴
Class<T>대신 KClass<T>를 사용한 경우
- Java에서 타입을 넘길 경우 String.class, User.class처럼 Class<T>를 사용
- Kotlin에서는 ::class를 사용하여 KClass<T>를 사용하고 .java를 붙이면 Java의 Class<T>로 변환 가능
KClass<T>
- Kotlin에서는 클래스 타입 정보를 ::class로 가져옴: KClass<T>
- Java의 Class<T>와 대응되는 방식
- 리프랙션을 할 때 자주 사용하며 Java interop을 위하여 .java로 변환하기도함
[예시]
User::class = KClass<User>
⭑ KClass글 추가 예정
import com.google.gson.Gson
import kotlin.reflect.KClass
fun <T : Any> fromJsonWithKClass(json: String, kClass: KClass<T>): T {
return Gson().fromJson(json, kClass.java) // Class<T>: kClass.java -> kClass
}
val json = """{"name": "희우", "age": 25}"""
val user = fromJsonWithKClass(json, User::class) // Class<T>: User::class -> User::class.java
reified를 사용한 경우
inline fun <reified T> fromJson(json: String): T{
return Gson().fromJson(json, T::class.java)
}
val json = """{"name":"희우","age":24}"""
val user = fromJson(json)
- T::class.java를 내부에서 직접 사용 가능
중첩 제네릭
- List<User>와 같이 복잡한 타입은 T::class.java로는 부족하여 TypeToken을 사용해야함
- reified로 완벽하게 해결하기 어려워 TypeToken을 따로 사용해야 할 수 있음
⭑ TypeToken 글 추가 예정
문제
1. reified를 활용한 타입 검사 함수 만들기
[요구사항]
checkType이라는 제네릭 확장 함수를 작성해보자.
fun <T> Any.checkType(): Boolean {
// 구현할 내용
}
- 호출한 객체가 제네릭 타입 T에 해당하는지 검사
- reified 키워드를 사용해서 구현
- is T를 활용
[사용 예시]
val value: Any = "Hello"
println(value.checkType<String>()) // true
println(value.checkType<Int>()) // false
답:
inline fun <reified T> Any.checkType(): Boolean {
return this is T
}
2. reified와 Class<T> 비교하여 클래스 이름 출력하기
inline fun <reified T> printClassName()
- T::class 와 T::class.java를 각각 출력하는 함수 구현
답:
inline fun <T: Any> printClassName(clazz: Class<T>) {
println("Kotlin class: ${clazz.kotlin}") // Kotlin class: class java.lang.String (Kotlin reflection is not available)
println("Java class: $clazz") //Java class: class java.lang.String
}
fun main(){
printClassName(String::class.java)
}
inline fun <reified T> printClassName() {
println("Kotlin class: ${T::class}") // Kotlin class: class java.lang.String (Kotlin reflection is not available)
println("Java class: ${T::class.java}") // Java class: class java.lang.String
}
fun main(){
printClassName<String>()
}
'개발새발 > 코틀린' 카테고리의 다른 글
[코틀린/Kotlin] 익명 클래스(Anonymous Class) (0) | 2025.09.04 |
---|---|
[코틀린/Kotlin] is, as, as? (0) | 2025.09.03 |
[코틀린/Kotlin] 메모이제이션(Memoization) (0) | 2025.09.02 |
[코틀린/Kotlin] 재귀(Recursion) (1) | 2025.09.01 |
[코틀린/Kotlin] 인라인 함수 (1) | 2025.09.01 |