코틀린 언어 정리 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)

}



+ Recent posts