티스토리 뷰
728x90
리플렉션
- 클래스, 함수, 프로퍼티의 런타임 표현에 접근할 수 있게 해준다.
1. KAnnotatedElement
annotation class Component(val name: String = "Core")
@Component("I/O")
class IO
fun main() {
val component = IO::class.annotations.first() as Component
println("Component name: ${component.name}") // Component name: Log
}
- 가장 상위 리플렉션 타입으로, 모든 리플렉션 타입의 부모가 된다.
- 함수, 프로퍼티, 클래스 등 요소에 정의된 어노테이션에 접근하는 기능을 제공한다.
- 어노테이션 인스턴스의 리스트 프로퍼티(annotations) 하나만을 가지고 있다.
- type alias에 붙은 어노테이션에 대한 리플렉션은 얻을 수 없다.
2. KClassifier
2-1. KClass
- 컴파일 시점의 클래스, 인터페이스, 객체 선언을 런타임에 표현한다.
- KClass 인스턴스를 얻는 방법
- 클래스 리터럴 구문 사용
fun main() {
println(String::class.isFinal) // true
println((1 + 2)::class) // class kotlin.Int
}
-
- kotlin 확장 프로퍼티 사용
fun main() {
// Class -> KClass
val stringClass = Class.forName("java.lang.String").kotlin
println(stringClass.isInstance("Hello")) // true
// KClass -> Class
println(String::class.java) // class java.lang.String
}
-
-
- java.lang.Class 인스턴스를 KClass 인스턴스로 변환
- java 프로퍼티를 사용하면 반대로 변환 가능
-
- 클래스 종류를 나타내는 프로퍼티들
val isAbstract: Boolean
val isCompanion: Boolean
val isData: Boolean
val isFinal: Boolean
val isInner: Boolean
val isOpen: Boolean
val isSealed: Boolean
- 클래스의 접근 제한자를 나타내는 visibility 프로퍼티 (KVisibility 이넘 값을 가짐)
enum class KVisibility {
PUBLIC,
PROTECTED,
INTERVAL,
PRIVATE
}
private class A
fun main() {
class B
println(A::class.visibility) // PRIVATE
println(B::class.visibility) // null
}
-
- 코드 내에서 접근 제한자를 표현할 수 없다면 null이 된다. (ex: local class)
- 클래스 이름을 나타내는 프로퍼티
val simpleName: String?
val qualifiedName: String?
fun main() {
println(Any::class.simpleName) // Any
println(Any::class.qualifiedName) // kotlin.Any
}
-
- simpleName: 클래스의 간단한 이름을 반환한다.
- qualifiedName: 클래스의 전체 경로가 들어간 이름을 반환한다.
- local class 등의 경우 최상위 경로에서 접근할 방법이 없으므로 null이 반환된다.
- isInstance()
fun main() {
println(String::class.isInstance("")) // true
println(String::class.isInstance(12)) // false
}
-
- 인자가 현재 클래스의 인스턴스인지 알려준다.
- 클래스 멤버 선언에 접근
val constructors: Collection<KFunction<T>> // 주생성자, 부생성자 반환
val members: Collection<KCallable<*>> // 멤버 함수, 프로퍼티 반환
val nestedClasses: Collection<KClass<*>> // nested class와 객체 반환
val typeParametes: List<KTypeParameter> // 타입 파라미터 반환
class Person(val firstName: String, val familyName: String)
fun main() {
// Person KClass
val personClass = Person::class
// 주생성자를 KFunction 타입으로 받아서 call()을 통해 실행
val person = personClass.constructors.first().call("John", "Doe") // Person 인스턴스
}
- objectInstance: 객체에 대한 KClass에서 실제 객체 인스턴스를 반환
sealed class Color
data class Red(val r: Int, val g: Int, val b: Int) : Color()
data class Orange(val r: Int, val g: Int, val b: Int) : Color()
data class Yellow(val r: Int, val g: Int, val b: Int) : Color()
fun main() {
val a = Color::class.sealedSubclasses
println(a.joinToString { "$it" }) // class Orange, class Red, class Yellow
}
- sealedSubclasses: selaed class인 경우 해당 클래스의 자식 클래스의 리스트를 반환 (List<KClass<out T>>)
open class A
open class B : A()
class C : B()
fun main() {
println(C::class.supertypes) // [A, B] (x), [B] (o)
}
- supertypes: 클래스가 직접 상속한 상위 타입만 반환. (List<KType>)
2-2. KTypeParameter
- 어떤 제네릭 선언의 타입 파라미터를 표현한다.
val isReified: Boolean
val name: String
val upperBounds: List<KType>
val variance: KVariance
- upperBounds: 상위 바운드 타입이 담긴 리스트 반환
interface MyMap<K : Any, out V>
fun main() {
val parameters = MyMap::class.typeParameters
// K: [kotlin.Any], V: [kotlin.Any?]
println(parameters.joinToString { "${it.name}: ${it.upperBounds}" })
}
-
- 디폴트 바운드가 Any?이기 때문에 빈 리스트일 수 없다.
- variance: KVariance 이넘 값으로 변성의 종류를 반환 (선언 지점 변성)
enum class KVariance {
INVARIANT,
IN,
OUT
}
- KType
val arguments: List<KTypeProjection> // 타입 프로퍼티에 전달된 실제 타입 인자 목록
val classifier: KClassifier? // 프로퍼티의 classifier (타입을 지정하는 클래스)
val isMarkedNullable: Boolean // 널 가능성
fun main() {
val type = typeOf<List<String>>() // KType
println(type.arguments) // String
println(type.classifier) // List
println(type.isMarkedNullable) // false
}
3. KCallable
- 어떤 결과를 얻기 위해 호출할 수 있는 함수나 프로퍼티를 제공한다.
- callable reference(::)를 사용해서 KCallable 인스턴스를 얻을 수 있다.
fun sum(a: Int, b: Int) = a + b
fun main() {
println(::sum.returnType) // Int
}
- 함수의 제한자를 알 수 있는 프로퍼티들
val isAbstract: Boolean
val isFinal: Boolean
val isOpen: Boolean
val isSuspend: Booelan
val visibility: KVisibility?
- 프로퍼티나 함수의 시그니처를 표현하는 프로퍼티들
val name: String
val typeParameters: List<KTypeParameter>
val parameters: List<KParameter>
val returnType: KType
fun sum(a: Int, b: Int) = a + b
fun main() {
println(::sum.name) // sum
println(::sum.typeParameters) // []
println(::sum.parameters) // [Int, Int]
println(::sum.returnType) // Int
}
- typeParameters: 함수의 제네릭 타입 파라미터
- parameters
val simple = 1 // 멤버 x, 확장 x
val Int.ext get() = this // 멤버 x, 확장 o
class A { val Int.memberExt get() = this } // 멤버 o, 확장 o
fun main() {
fun printParams(callable: KCallable<*>) {
println(callable.parameters.joinToString { it.type.toString() })
}
printParams(::simple) // []
printParams(Int::ext) // [Int]
printParams(A::class.members.first()) // [A, Int]
}
-
- 멤버 함수/프로퍼티거나 확장 함수/프로퍼티인 경우 첫 번째 원소는 receiver
- 멤버인 동시에 확장인 경우 두 번째 원소도 receiver
- call()
fun sum(a: Int, b: Int) = a + b
val i get() = 10
fun main() {
println(::sum.call(5, 3)) // 8
println(::i.call()) // 10
}
-
- KCallable의 선언을 동적으로 호출할 수 있게 해주는 멤버 함수
- 함수인 경우 함수를 호출, 프로퍼티인 경우 게터를 호출한다.
- KParameter: 멤버/확장의 receiver, 함수/생성자의 파라미터에 대한 정보
val index: Int
val isOptional: Boolean
val isVararg: Boolean
val name: String?
val type: KType
val kind: KParamter
-
- isOptional: 파라미터에 디폴트 값이 있는지 여부
- kind
- INSTANCE: 멤버 receiver
- EXTENSION_RECEIVER: 확장 receiver
- VALUE: 그 외 일반적인 파라미터
- KProperty
val isConst: Boolean
val isLateinit: Boolean
var value = 1
fun main() {
println(::value.getter()) // 1
::value.setter(2)
println(value) // 2
}
-
- getter()를 통해 프로퍼티 게터 접근
- KMutableProperty의 경우 setter()를 통해 세터 호출
- KFunction: 함수나 생성자를 표현
val isInfix: Boolean
val isInline: Boolean
val isOperator: Boolean
val isSuspend: Boolean
-
- 함수의 종류를 알 수 있는 프로퍼티만 존재한다.
- isAccessible
class A(private val secret: String)
fun main() {
val a = A("Hello")
val s = A::class.members.first() as KProperty1<A, String>
s.isAccessible = true
println(s.get(a)) // Hello
}
-
- 이 프로퍼티를 통해 접근이 제한된 KCallable에 접근할 수 있다.
728x90
'kotlin' 카테고리의 다른 글
[kotlin/코틀린] 위임 프로퍼티 (0) | 2023.07.19 |
---|---|
[kotlin/코틀린] 연산자 오버로딩 (0) | 2023.07.19 |
[kotlin/코틀린] 어노테이션 (0) | 2023.07.19 |
[kotlin/코틀린] 제네릭 (0) | 2023.07.19 |
[kotlin/코틀린] 컬렉션 (0) | 2023.07.19 |