코틀린 언어 정리 5-2
Reflection
Callable References
프로그램 구조 조사 이외에 함수나 프로퍼티, 생성자에 대한 참조를 구하여 호출(사용)할 수 있습니다.
Function References
문법
::[function name]
예제 1
fun test () { fun sum ( a: Int, b: Int ) = a + b
var func = ::sum println( func(10, 20) ) } |
예제 2
fun test () { fun sum ( a: Int, b: Int ) = a + b fun sum ( a: Double, b: Double ) = a + b
// 함수 이름이 동일한 경우 변수의 타입으로 추론하여 선택 var func: ( Int, Int )-> Int = ::sum var func1: ( Double, Double )-> Double = ::sum var value = func(10, 20) var value1 = func1(10.0, 20.0)
println(value) println(value1) } |
함수 이름이 겹치는 경우(오버로딩 상황) 대입 변수 등의 타입 추론으로 함수를 선택 합니다.
리턴 객체
KFunction<out R>
매개 변수가 여러개인 경우 KFunction3<T1, T2, T3, R> 와 같은 형식 입니다. 여기서 T1~T3 등은 매개변수 타입, R은 리턴 타입 입니다.
Property References
문법
전역 프로퍼티
::[property name]
예제
import kotlin.reflect.KClass
var value: String = "abc" fun test () { //val value: String = "aaa" // 로컬 변수는 Property Reference를 구할 수 없음
println(::value.name) println(::value.get()) println(::value.set("def")) println(::value) } |
함수 내 로컬 변수
지원 하지 않습니다. 로컬 변수에서는 Property Reference를 구할 수 없습니다.
클래스 멤버 프로퍼티 및 확장 프로퍼티(extension property)
[class name]::[property name]
예제 1
import kotlin.reflect.KClass import kotlin.reflect.KCallable import kotlin.reflect.KProperty import kotlin.reflect.KFunction
class Normal ( var value: String )
fun test () { var obj = Normal("aa") println(Normal::value.get(obj)) println(Normal::value.set(obj, "bb")) println(obj.value) println(Normal::value.get(obj))
var valueL = Normal::value println(valueL.get(obj)) } |
프로퍼티의 get / set 호출 시 this에 해당되는 객체를 인수로 입력해 주어야 합니다.
예제 2
import kotlin.reflect.KClass import kotlin.reflect.KCallable import kotlin.reflect.KProperty import kotlin.reflect.KFunction
class Normal ( var value: String )
val Normal.valueE: Int get() = this.value.length
fun test () { var obj = Normal("aaa") println(obj.value.length) println(obj.valueE) var valueE = Normal::valueE // 확장 프로퍼티의 KProperty<T> 도 클래스 멤버 프로퍼티와 동일한 방법으로 구합니다. println(valueE.get(obj)) } |
리턴 객체
val
프로퍼티가 val로 선언된 경우 KProperty<T>
var
프로퍼티가 var로 선언된 경우 KMutableProperty<T>
Interoperability With Java Reflection( Java Reflection 기능과 연동 )
Java platform에서 표준 라이브러리는 Java reflection 과의 상호 연동을 위한 기능을 제공합니다. (kotlin.reflect.jvm 참조)
예제
import kotlin.reflect.jvm.*
class Normal ( var value: String ) {}
//fun main (args: Array<String> ) { fun test () { println(Normal::value.javaGetter) println(Normal::value.javaField) var obj = Normal("javaField test") println(obj::class == obj.javaClass.kotlin) println(Normal::class == obj::class) println(obj.value) } |
Constructor References
생성자도 함수나 프로퍼티처럼 참조될 수 있습니다. 함수 타입의 객체로 사용할 수 있으며 리턴 값은 생성한 객체입니다.
문법
::[class name]
클래스에 생성자가 1개인 경우, 클래스 이름 앞에 :: 연산자만 사용하면 생성자를 가져올 수 있습니다.
예제 1
import kotlin.reflect.KClass import kotlin.reflect.KCallable import kotlin.reflect.KProperty import kotlin.reflect.KFunction
class Normal ( var value: String ) class Normal0() {} //fun main (args: Array<String> ) { fun test () { var obj = Normal("aaa") println(obj.value)
var cons1 = ::Normal // Normal class의 생성자(생성자가 1개만 있을 경우 가능한 문법) println(cons1) var obj1 = cons1("bbb") println(obj1.value)
var cons2: ( String )-> Normal = ::Normal // Normal class의 생성자를 명시적으로 대입 println(cons2) var obj2 = cons2("BBB") println(obj2.value)
//var obj_2 = function(::Normal0) // kotlin 사이트에 있는 예제인데 작동 안함 //println(obj_2.value) } |
예제 2
//import jdk.nashorn.internal.objects.NativeFunction.function import kotlin.reflect.KClass import kotlin.reflect.KCallable import kotlin.reflect.KProperty import kotlin.reflect.KFunction
class Normal ( var value: String ) { var num: Int = 0 constructor ( num: Int ): this ("Normal::value") { this.num = num } } class Normal0() { var value: String = "Normal0:value" }
//fun main (args: Array<String> ) { fun test () { var obj = Normal("aaa") println(obj.value)
//var cons1 = ::Normal // Normal class의 생성자가 2개 이상인 경우 컴파일 에러 var cons1: ( String )-> Normal = ::Normal println(cons1) var obj1 = cons1("bbb") println(obj1.value)
var cons1_1: (Int)-> Normal = ::Normal println(cons1_1) var obj1_1 = cons1_1(10) println(obj1_1.num)
//var obj_2 = function(::Normal0) // 매개변수가 없는 생성자는 이 방식으로 호출 가능하다고 나와 있으나 컴파일 에러 발생함 //println(obj_2.value) } |
생성자(constructor)가 2개 이상인 경우 ::ClassName 구문 만으로는 생성자를 특정할 수 없기 때문에 사용이 불가능합니다. 생성자의 타입을 추론할 수 있는 구문(type을 명시한 변수 선언 등)을 사용해야 합니다.
Bound Function and Property References
예제
class Normal ( var value: String ) { var num: Int = 0 constructor ( num: Int ): this("Normal default") { this.num = num }
fun func_setValue () { value = "from setValue default" }
fun func_setValue ( value: String ) { this.value = value }
inner class NormalInner ( var valueInner: String ) {} }
//fun main (args: Array<String> ) { fun test () { var num = Normal::num var obj = Normal("Test") // 명시적 타입 선언으로 overloading 함수를 구분 var funcObj_setValue1: ()-> Unit = obj::func_setValue // 객체를 이용해 멤버 함수를 참조하는 방법 println(obj.value) funcObj_setValue1() println(obj.value) var func_setValue1: (Normal)-> Unit = Normal::func_setValue // 클래스 이름을 이용해 멤버 함수를 참조하는 방법. 객체를 첫번째 매개변수로 전달 받아야 합니다. obj.value = "Test"; println(obj.value) func_setValue1(obj) println(obj.value)
// 프로퍼티도 object 또는 class를 이용하여 함수와 동일한 방식으로 참조할 수 있습니다. var propObj_num = obj::num println(propObj_num) println(propObj_num.get())
var prop_num = Normal::num println(prop_num) println(prop_num.get(obj))
// 명시적 타입 선언으로 overloading 함수를 구분 var funcObj_setValue2: ( String )-> Unit = obj::func_setValue funcObj_setValue2("from funcObj_setValue") println(obj.value) var func_setValue2: ( Normal, String )-> Unit = Normal::func_setValue func_setValue2(obj, "from func_setValue") println(obj.value)
var constructor_Normal: ( Int )-> Normal = ::Normal // 일반 생성자 참조. 변수는 멤버 함수와 동일한 방법으로 선언합니다. println(constructor_Normal(10))
var constructor_NormalInner: ( String )-> Normal.NormalInner = obj::NormalInner // outer class의 인스턴스와 inner class name으로 생성자를 참조하는 방법 println(obj.NormalInner("NormalInner from obj.NormalInner").valueInner) println(constructor_NormalInner("NormalInner from constructor_NormalInner = obj::NormalInner").valueInner) } |
멤버 함수 및 멤버 프로퍼티
[obj]::[function name]
var func: ( Int )-> Unit = Normal::func1
var prop = Normal::value
println(prop.get(obj))
객체를 이용해 멤버 함수 및 프로퍼티를 변수로 참조할 때에는 클래스 내에 선언한 멤버함수 형식을 그대로 사용하면 됩니다.
[classname]::[function name]
var funcObj: ( Normal, Int )-> Unit = obj::func1
var propObj = obj::value
println(propObj.get())
클래스 이름을 이용해 멤버 함수를 변수로 참조할 때에는 원래의 함수 매개변수 선언 이외에 맨 앞에 this로 사용할 매개변수를 추가해 주어야 합니다. 멤버 프로퍼티는 객체와 마찬가지로 선언하고, get / set 등을 호출할 때 this로 사용할 객체를 첫번째 매개 변수로 추가해 주어야 합니다.
생성자
::[class name]
var cons = ::Normal
또는
var cons: ( value: String )-> Unit = ::Normal
생성자가 오버로딩 되어 여러 개 존재할 때에는 생성자를 대입할 변수의 타입을 명시적으로 선언해야 합니다.
Bound constructor References
nested class의 생성자
[outer class name]::[nested class name]
var cons: ( Int )->Normal.NormalNested = Normal::NormalNested
생성자의 리턴 타입 문법이 Normal::NormalNested 가 아니라 Normal.NormalNested인 점에 주의해야 합니다.
생성자 참조: Normal::NormalNested
클래스 참조: Normal.NormalNested
생성자의 리턴 타입은 nested class와 inner class 에서 모두 동일한 문법을 사용합니다.
예제
import kotlin.reflect.KClass
class Normal {
class NormalNested ( val value: Int ) { init { println("NormalNested:Primary $value") }
constructor ( valueS: String ): this(0) { println("NormalNested::secondary $valueS") } } }
fun test () { var cons_Normal = ::Normal var cons_NormalNested_p: (Int)->Normal.NormalNested = Normal::NormalNested var cons_NormalNested_s: (String)->Normal.NormalNested = Normal::NormalNested
cons_NormalNested_p(10) cons_NormalNested_s("string 10")
println(cons_Normal) println(cons_NormalNested_p) println(cons_NormalNested_s) } |
inner class의 생성자
[outer class 객체]::[inner class name]
var cons: ( String )-> Normal.NormalInner = obj::NormalInner
inner class 는 outer class의 프로퍼티 등을 참조할 수 있으므로 단독으로 생성할 수 없습니다. 따라서 outer class가 아닌 outer 객체를 통해 참조 해야 합니다.
예제
class Normal ( var value: String ) { var num: Int = 0 constructor ( num: Int ): this("Normal default") { this.num = num }
inner class NormalInner ( var valueInner: String ) {} }
//fun main (args: Array<String> ) { fun test () { var obj = Normal("Test") var constructor_Normal: ( Int )-> Normal = ::Normal // 일반 생성자 참조. 변수는 멤버 함수와 동일한 방법으로 선언합니다. println(constructor_Normal(10))
var constructor_NormalInner: ( String )-> Normal.NormalInner = obj::NormalInner // outer class의 인스턴스와 inner class name으로 생성자를 참조하는 방법 println(obj.NormalInner("NormalInner from obj.NormalInner").valueInner) println(constructor_NormalInner("NormalInner from constructor_NormalInner = obj::NormalInner").valueInner) } |