티스토리 뷰
리플렉션(Reflection)은 런타임 때 프로그램의 구조(객체, 함수, 프로퍼티)를 분석해 내는 기법을 이야기합니다. 코틀린에서 리플렉션을 위해서는 라이브러리가 필요합니다. kotlin-reflect.jar 라는 라이브러리를 의존성(dependency) 설정을 통해 준비해야 합니다
dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect"
}
1. 클래스 타입과 레퍼런스
런타임 때 동적으로 클래스를 분석하려면 클래스에 대한 정보가 필요한데 이 클래스에 대한 정보를 클래스 레퍼런스라고 표현하며, 클래스 레퍼런스를 대입하는 곳은 클래스 타입으로 선언해야 합니다. 클래스 타입은 KClass<*>로 표현하며 대입하는 클래스 레퍼런스는 "클래스명::class"로 표현합니다
// KClass<*> 타입
val myVal: KClass<*> = String::class
fun myFun(arg: KClass<*>) {
}
위 소스에서 클래스 타입을 KClass<*>로 작성했는데 이 타입에는 어떤 클래스 레퍼런스도 대입할 수 있습니다. 예를 들어, KClass<String>으로 명시하면 String 클래스의 레퍼런스만 등록할 수 있습니다. 또한, 클래스 레퍼런스는 코틀린 클래스와 자바 클래스가 다른데 코틀린 클래스는 "클래스명::class"로 표현하며 자바 클래스는 "클래스명::class.java"로 표현합니다
// 클래스 타입
val myVal: KClass<String> = String::class
val myVal2: KClass<String> = Double::class // error
val myVal3: Class<*> = String::class.java
위와 같이 자바 클래스를 받으려면 클래스 타입을 Class<*>로 선언해야 합니다
2. 클래스 정보 분석
// 클래스 정보 분석
open class MyClass
fun someFun(arg: KClass<*>) {
println("class info")
println("isAbstract : ${arg.isAbstract}") // 클래스가 abstract로 선언되었는지 판단
println("isCompanion : ${arg.isCompanion}") // 클래스가 companion로 선언되었는지 판단
println("isData : ${arg.isData}") // 클래스가 data로 선언되었는지 판단
println("isFinal : ${arg.isFinal}") // 클래스가 final로 선언되었는지 판단
println("isInner : ${arg.isInner}") // 클래스가 inner로 선언되었는지 판단
println("isOpen : ${arg.isOpen}") // 클래스가 open으로 선언되었는지 판단
println("isSealed : ${arg.isSealed}") // 클래스가 sealed로 선언되었는지 판단
}
someFun(MyClass::class)
// class info
// isAbstract : false
// isCompanion : false
// isData : false
// isFinal : false
// isInner : false
// isOpen : true
// isSealed : false
3. 생성자 분석
// 생성자 정보 분석
open class MyClass(no: Int) {
constructor(no: Int, name: String): this(10) {}
constructor(no: Int, name: String, email: String): this(10) {}
}
fun someFun(arg: KClass<*>) {
val constructors = arg.constructors // 모든 생성자 정보
for (constructor in constructors) {
print("constructor...")
val parameters = constructor.parameters
for (parameter in parameters) {
print("${parameter.name}: ${parameter.type} .. ");
}
println()
}
print("primary constructor...")
val primaryConstructor = arg.primaryConstructor // 주 생성자 정보
if (primaryConstructor != null) {
val parameters = primaryConstructor.parameters
for (parameter in parameters) {
print("${parameter.name}: ${parameter.type} .. ");
}
}
}
someFun(MyClass::class)
// constructor...no: kotlin:Int .. name: kotlin:String ..
// constructor...no: kotlin:Int .. name: kotlin:String .. email: kotlin.String ..
// constructor...no: kotlin:Int ..
// primary constructor...no: kotlin:Int ..
4. 클래스 프로퍼티 분석
open class SuperClass {
val superVal: Int = 10
}
class MyClass(val no: Int): SuperClass() {
val myVal: String = "hello"
val String.someVal: String
get() = "world"
}
fun someFun(arg: KClass<*>) {
// 확장 프로퍼티를 제외한 클래스에 선언된 모든 프로퍼티 반환
val properties = arg.declaredMemberProperties
println("declaredMemberProperties")
for (property in properties) {
println("${property.name}: ${property.returnType} .. ")
}
// 확장 프로퍼티를 제외한 클래스와 상위 클래스에 선언된 모든 프로퍼티 반환
val properties2 = arg.memberProperties
println("memberProperties")
for (property in properties2) {
println("${property.name}: ${property.returnType} .. ")
}
// 클래스에 선언된 확장 프로퍼티 반환
val properties3 = arg.declaredMemberExtensionProperties
println("declaredMemberExtensionProperties")
for (property in properties3) {
println("${property.name}: ${property.returnType} .. ")
}
}
someFun(MyClass::class)
// declaredMemberProperties
// myVal: kotlin.String ..
// no: kotlin.Int ..
// memberProperties
// myVal: kotlin.String ..
// no: kotlin.Int ..
// superVal: kotlin.Int ..
// declaredMemberExtensionProperties
// someVal: kotlin.String ..
5. 클래스 함수 분석
// 함수 정보 분석
open class SuperClass {
fun superFun() {}
}
class MyClass: SuperClass() {
fun myFun() {}
fun String.someFun() {}
}
fun someFun(arg: KClass<*>) {
// 확장 함수를 제외한 클래스에 선언된 모든 함수 반환
val functions = arg.declaredMemberFunctions
println("declaredFunctions")
for (function in functions) {
println("${function.name}: ${function.returnType} .. ")
}
// 확장 함수를 제외한 클래스와 상위 클래스에 선언된 모든 함수 반환
val functions2 = arg.memberFunctions
println("memberFunctions")
for (function in functions2) {
println("${function.name}: ${function.returnType} .. ")
}
// 클래스에 선언된 확장 함수 반환
val functions3 = arg.declaredMemberExtensionFunctions
println("declaredMemberExtensionFunctions")
for (function in functions3) {
println("${function.name}: ${function.returnType} .. ")
}
}
someFun(MyClass::class)
// declaredFunctions
// myFun: kotlin.Unit
// memberFunctions
// myFun: kotlin.Unit
// equals: kotlin.Boolean
// hashCode: kotlin.Int
// superFun: kotlin.Unit
// toString: kotlin.String
// declaredMemberExtensionFunctions
// someFun: kotlin.Unit
6. 함수 레퍼런스 분석
// 함수 레퍼런스
fun myFun() {}
class MyClass {
fun myFun2() {}
}
val funReference: KFunction<*> = ::myFun
val funReference2: KFunction<*> = MyClass::myFun2
위와 같이 함수 레퍼런스를 KFuntion 타입으로 표현하면 KFunction 프로퍼티를 이용해 함수의 다양한 정보(name(함수 이름), parameters(매개변수), returnType(반환 타입))를 추출할 수 있습니다
// 고차 함수 이용
fun myFun(no: Int): Boolean {
return no > 10
}
val array = arrayOf<Int>(10, 5, 30, 15)
array.filter(::myFun).forEach{ println(it) }
// 30
// 15
7. 프로퍼티 레퍼런스 분석
프로퍼티 레퍼런스는 두 가지 타입으로 표현하는데 KProperty<*>와 KMutableProperty<*>입니다. val로 선언한 프로퍼티는 KProperty, var로 선언한 프로퍼티는 KMutableProperty로 표현합니다
// 프로퍼티 정보 분석
val myVal: Int = 3
var myVar: Int = 5
class MyClass {
val objVal: Int = 10
var objVar: Int = 20
}
fun reflectionProperty(obj: Any?, arg: KProperty<*>) {
println("property name: ${arg.name}, property type: ${arg.returnType}")
if (obj != null) {
println(arg.getter.call(obj))
} else {
println(arg.getter.call())
}
}
fun reflectionMutableProperty(obj: Any?, arg: KMutableProperty<*>) {
println("property name: ${arg.name}, property type: ${arg.returnType}")
if (obj != null) {
arg.setter.call(obj, 40)
println(arg.getter.call(obj))
} else {
arg.setter.call(40)
println(arg.getter.call())
}
}
reflectionProperty(null, ::myVal)
reflectionMutableProperty(null, ::myVar)
val obj: MyClass = MyClass()
reflectionProperty(obj, MyClass::objVal)
reflectionMutableProperty(obj, MyClass::objVar)
// property name: myVal, property type: kotlin.Int
// 3
// property name: myVar, property type: kotlin.Int
// 40
// property name: objVal, property type: kotlin.Int
// 10
// property name: objVar, property type: kotlin.Int
// 40
'코틀린' 카테고리의 다른 글
[코틀린] 코틀린의 코루틴(Coroutine) (0) | 2019.05.17 |
---|---|
[코틀린] 코틀린의 제네릭(Generics) (0) | 2019.05.17 |
[코틀린] 카카오톡의 서버 사이드 코틀린, if kakao 개발자 컨퍼런스 (0) | 2019.05.17 |
- Total
- Today
- Yesterday
- 유니티
- 자바
- 백그라운드
- ScrollView in ScrollView
- 구글IO
- google I/O
- Material
- 알고리즘
- 신규기능
- Unity
- Java
- 개발
- 안드로이드
- 카카오톡
- 과제
- Kotlin
- Android
- 앱
- 코틀린
- 백준
- NestedScrollView
- 안드로이드Q
- 안드로이드 9.0
- KAKAO
- 카톡
- 중첩
- ScrollView
- kakaotalk
- 대학교
- 액티비티
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |