티스토리 뷰
Reflection
리플렉션은 프로그램의 구조를 런타임에 살펴볼 수 있는 언어 및 라이브러리 기능들의 집합이다.
Kotlin에서 함수와 속성은 일급 객체이며, 이들을 런타임에 조사할 수 있는 능력은 함수형 또는 리액티브 스타일 프로그래밍을 할 때 중요하다.
JVM 의존성
JVM 플랫폼에서, Kotlin 컴파일러에는 리플렉션 기능을 사용하기 위해 필요한 런타임 컴포넌트가 별도의 아티팩트(kotlin-reflect.jar)로 포함되어 있다. 이는 리플렉션 기능을 사용하지 않는 애플리케이션의 런타임 라이브러리 크기를 줄이기 위해서다.
Gradle이나 Maven 프로젝트에서 리플렉션 사용하기
dependencies {
implementation(kotlin("reflect"))
}
기타
- Gradle이나 Maven을 사용하지 않는 경우, 프로젝트 classPath에
Kotlin-reflect.jar가 포함되어 있어야한다. - 커멘드 라인 컴파일러나 Ant를 사용하는 인텔리제이 같은 IDEA 프로젝트 등에서는 기본적으로 포함되어있다.
- 커멘드 라인 컴파일러나 Ant에서는
-no -reflect컴파일 옵션을 사용하면kotlin-reflect.jar를 classPath에서 제외할 수 있다.
클래스 참조
가장 기본적인 리플렉션 기능은 Kotlin 클래스의 런타임 참조를 얻는 것이다. 정적으로 알려진 Kotlin 클래스의 참조를 얻으려면, 클래스 리터럴 문법(class literal syntax)을 사용할 수 있다.
val c = MyClass::class
이때 얻는 참조는 KClass타입이다.
JVM에서 주의할 점
Kotlin 클래스 참조(Kclass)는 Java 클래스 참조(Class)와 동일하지 않다. Java클래스 참조(Class)와 동일하지 않다. Java 클래스 참조가 필요하면, KClass 인스턴스의 .java 프로퍼티를 사용하면 된다.
val javaClass = MyClass::class.java
바운드 클래스 참조
특정 객체의 클래스 참조도 동일하게 ::class 문법을 사용하여 얻을 수 있다. 객체를 리시버로 사용하면 된다.
val widget: Widget = ...
assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
함수 참조
다음과 같은 함수가 있다고 가정하자
fun isOdd(x: Int) = x % 2 != 0
이를 isOdd(5)로 호출할 수 있지만, 다음과 같이 함수를 함수 타입 값으로 사용하여 다른 함수에 전달할 수 있다.
val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd))
여기서 ::isOdd는 (Int) -> Boolean 타입의 값이다.
프로퍼티 참조
프로퍼티를 일급 객체로 다루려면 ::연산자를 사용한다.
val x = 1
fun main() {
println(::x.get())
println(::x.name)
}
여기서 ::x 표현식은 KProperty0<Int> 타입의 프로퍼티 객체로 평가된다. get()으로 값을 읽거나 name 속성을 통해 프로퍼티 이름을 가져올 수 있다.
Java 리플렉션과의 상호운용성
JVM에서는, 코틀린 표준 라이브러리가 Java 리플렉션 객체 ↔ Kotlin 객체 간 매핑을 지원하는 확장함수를 제공한다.
예제를 들면 다음과 같다.
import kotlin.reflect.jvm.*
class A(val p: Int)
fun main() {
println(A::p.javaGetter) // 출력: "public final int A.getP()"
println(A::p.javaField) // 출력: "private final int A.p"
}
A::p.javaGetter는 해당 프로퍼티의 Java getter 메서드를 반환한다.
A::p.javaField는 해당 프로퍼티의 실제 baking field를 반환한다.
Java 클래스 ↔ Kotlin 클래스
Java 클래스에서 대응되는 Kotlin 클래스(Kclass)를 얻고 싶다면 .kotlin확장프로퍼티를 사용한다.
fun getKClass(o: Any): KClass<Any> = o.javaClass.kotlin
즉 o.javaClass는 Java Class<?>객체이며 o.javaClass.Kotlin은 KClass객체이다.
생성자 참조
생성자도 함수나 프로퍼티처럼 참조 가능하다. 즉, 특정 함수 타입을 기대하는 곳에, 생성자를 그대로 전달해서 사용할 수 있다. 생성자 참조는 :: 연산자 뒤에 클래스 이름을 붙여 사용한다.
예제 코드는 다음과 같다.
class Foo
fun function(factory: () -> Foo) {
val x: Foo = factory()
}
여기서 function은 Foo 타입 객체를 반환하는 함수를 인자로 받고 있다. 따라서 Foo 클래스의 인자가 없는 기본 생성자를 참조해서 넘겨줄 수 있다.
'코틀린' 카테고리의 다른 글
| StateFlow, SharedFlow (0) | 2025.11.18 |
|---|---|
| 디미터의 법칙 (0) | 2025.03.30 |
| 코틀린 문법(Sealed Interface) (0) | 2025.03.30 |
| 코틀린 문법(배열) (0) | 2024.08.19 |
| Kotlin에서 property, JAVA에서의 field와 property (0) | 2024.08.05 |