Search

Reflection

리플렉션은 프로그램의 구조를 런타임에 반영할 수 있는 언어 및 라이브러리 기능의 집합이다.
함수와 속성은 Kotlin에서 일급 객체이며 런타임에 속성이나 함수의 이름 또는 타입을 알 수 있는 기능은 함수형 또는 반응형 스타일을 사용할 때 필수적이다.
Kotlin/JS는 리플렉션 기능에 대한 제한된 지원을 제공한다.

JVM 종속성

JVM 플랫폼에서 코틀린 컴파일러 배포판에는 리플렉션 기능을 사용하기 위해 필요한 런타임 구성 요소인 kotlin-relfect.jar 가 별도로 포함되어 있다.
이는 리플렉션 기능을 사용하지 않는 어플리케이션의 런타임 라이브러리 크기를 줄이기 위해서이다.
//Gradle dependencies { implementation(kotlin("reflect")) } //Maven <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId> </dependency> </dependencies>
Kotlin
복사
Gradle 또는 Maven 프로젝트에서 리플렉션을 사용하려면 kotlin-reflect에 대한 종속성을 추가하라.
Gradle 또는 Maven 프로젝트를 사용하지 않는 경우 프로젝트의 클래스 경로에 kotlin-reflect.jar가 포함되어 있는지 확인하라.

클래스 참조

가장 기본적인 리플렉션 기능은 코틀린 클래스에 대한 런타임 참조를 얻는 것이다.
정적으로 알려진 코틀린 클래스에 대한 참조를 얻으려면 클래스 리터럴 구문을 사용할 수 있다.
val c = MyClass::class
Kotlin
복사
이 참조는 KClass 타입 값이다.
JVM에서는 코틀린 클래스 참조가 자바 클래스 참조와 다르다.
자바 클래스 참조를 얻으려면 KClass 인스턴스에서 .java 속성을 사용하라.

바운드 클래스 참조

특정 객체의 클래스 참조를 얻으려면 동일한 ::class 구문을 사용하여 객체를 수신자로 사용할 수 있다.
val widget: Widget = ... assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
Kotlin
복사
위 코드는 GoodWidget 또는 BadWidget 과 같은 객체의 정확한 클래스 참조를 얻는다.

호출 가능한 참조

함수, 속성 및 생성자에 대한 참조는 함수 타입의 인스턴스로 호출하거나 사용할 수 있다.
모든 호출 가능한 참조의 공통 슈퍼타입은 KCallable<out R> 이며 여기서 R은 반환 값 타입이다.
이는 속성 타입이자 생성자에 대한 생성 타입이다.

함수 참조

fun isOdd(x: Int) = x % 2 != 0
Kotlin
복사
위와 같이 선언된 명명된 함수를 가진 경우 직접 호출할 수 있다.
val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd))
Kotlin
복사
:: 연산자를 사용하면 함수 타입 값으로 사용하여 다른 함수에 전달할 수 있다.
::isOdd 는 함수 타입 (Int) → Boolean 의 값이다.
함수 참조는 매개변수 수에 따라 KFunction<out R> 의 하위 타입 중 하나에 속한다.
fun isOdd(x: Int) = x % 2 != 0 fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd)) // refers to isOdd(x: Int)
Kotlin
복사
오브로드된 함수와 함께 :: 를 사용할 수 있으며 문맥에서 타입이 추론 가능해야 한다.
val predicate: (String) -> Boolean = ::isOdd // refers to isOdd(x: String)
Kotlin
복사
필요한 문맥을 제공하여 변수를 명시적으로 지정할 수도 있다.
val isEmptyStringList: List<String>.() -> Boolean = List<String>::isEmpty
Kotlin
복사
클래스의 멤버나 확장 함수에 대해 사용하려면 String::toCharArray 처럼 한정해야 한다.
확장 함수 타입을 가진 변수를 초기화할 때 추론된 함수 타입에는 수신자가 없지만 수신자 객체를 받는 추가 매개변수가 포함된다.
수신자를 가진 함수 타입을 얻으려면 타입을 명시적으로 지정하라.

함수 조합

fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C { return { x -> f(g(x)) } } fun length(s: String) = s.length val oddLength = compose(::isOdd, ::length) val strings = listOf("a", "ab", "abc") println(strings.filter(oddLength))
Kotlin
복사
compose 함수는 전달된 두 함수의 조합을 반환한다.

속성 참조

val x = 1 fun main() { println(::x.get()) println(::x.name) }
Kotlin
복사
Kotlin에서 속성을 일급 객체로 접근하려면 :: 연산자를 사용하라.
::x 표현식은 KProperty0<Int> 타입 속성 객체로 평가된다.
get() 메서드를 사용하여 값을 읽거나 name 속성을 사용하여 속성 이름을 검색할 수 있다.
var y = 1 fun main() { ::y.set(2) println(y) }
Kotlin
복사
::y 표현식은 set() 메서드를 가진 KMutableProperty0<Int> 타입을 반환한다.
val strs = listOf("a", "bc", "def") println(strs.map(String::length))
Kotlin
복사
속성 참조는 단일 제네릭 매개변수가 필요한 함수로 사용될 수 있다.
class A(val p: Int) val prop = A::p println(prop.get(A(1)))
Kotlin
복사
클래스의 멤버인 속성에 접근하려면 위처럼 한정하라.
val String.lastChar: Char get() = this[length - 1] fun main() { println(String::lastChar.get("abc")) }
Kotlin
복사
확장 속성에 대한 예시는 위와 같다.

자바 리플렉션과 상호 운용성

JVM 플랫폼에서 표준 라이브러리는 자바 리플렉션 객체와의 매핑을 제공하는 리플렉션 클래스의 확장을 포함한다.
import kotlin.reflect.jvm.* class A(val p: Int) fun main() { println(A::p.javaGetter) // prints "public final int A.getP()" println(A::p.javaField) // prints "private final int A.p" }
Kotlin
복사
코틀린 속성의 게터로 작동하는 자바 메서드 또는 백킹 필드를 찾으려면 .javaGetter.javaField 확장 속성을 사용하라.
fun getKClass(o: Any): KClass<Any> = o.javaClass.kotlin
Kotlin
복사
자바 클래스에 해당하는 코틀린 클래스를 얻으려면 .kotlin 확장 속성을 사용하라.

생성자 참조

생성자는 메서드와 속성과 마찬가지로 참조할 수 있다.
생성자와 같은 매개변수를 받는 함수 타입 객체가 필요할 때 사용할 수 있다.
class Foo fun function(factory: () -> Foo) { val x: Foo = factory() } function(::Foo)
Kotlin
복사
생성자는 :: 연산자를 사용하여 클래스 이름을 추가하여 참조한다.
생성자에 대한 호출 참조는 매개변수 수에 따라 KFunction<out R> 의 하위 타입으로 분류된다.

바운드 함수 및 속성 참조

특정 객체의 인스턴스 메서드를 참조할 수 있다.
val numberRegex = "\\d+".toRegex() println(numberRegex.matches("29")) val isNumber = numberRegex::matches println(isNumber("29")) val strings = listOf("abc", "124", "a70") println(strings.filter(numberRegex::matches))
Kotlin
복사
matches 메서드를 직접 호출하는 대신 그 참조를 사용한다.
이러한 참조는 수신자에 바인딩된다.
이 참조는 위 예시처럼 직접 호출할 수 있거나 함수 타입 표현식이 필요한 곳에서 사용할 수 있다.
val isNumber: (CharSequence) -> Boolean = numberRegex::matches val matches: (Regex, CharSequence) -> Boolean = Regex::matches
Kotlin
복사
바운드 참조와 언바운드 참조의 타입을 비교하면 바운드 호출 참조는 수신자가 부착되어 있기 때문에 수신자의 타입은 더 이상 매개변수가 아니다.
val prop = "abc"::length println(prop.get())
Kotlin
복사
속성 참조도 바인딩 할 수 있다.
이 경우 수신자를 명시할 필요는 없다. (this::foo 와 ::foo 는 동일하게 동작)

바운드 생성자 참조

class Outer { inner class Inner } val o = Outer() val boundInnerCtor = o::Inner
Kotlin
복사
내부 클래스의 생성자에 대한 바운드 호출 참조는 외부 클래스의 인스턴스를 제공함으로써 얻을 수 있다.