class MyClass {
private fun secretMethod(message: String): String {
return "Secret message: $message"
}
}
fun main() {
val myClassInstance = MyClass()
// Cannot access 'secretMethod': it is private in 'MyClass'kotlin(INVISIBLE_MEMBER)
val result = myClassInstance.secretMethod("I am hungry.")
}
Kotlin에서 private 메서드는 기본적으로 클래스 외부에서 접근할 수 없다. 하지만 reflection을 사용하면 런타임에 클래스의 메타데이터에 접근하여 이러한 제한을 우회할 수 있다.
Reflection은 클래스, 메서드, 필드 등의 정보를 런타임에 동적으로 가져오거나 조작할 수 있다.
Kotlin 클래스에서 Java의 리플렉션 API를 사용하려면 먼저 KClass를 Java의 Class 객체로 변환해야 한다.
val clazz = MyClass::class.java
객체에서 getDeclaredMethod()를 이용해 호출하려는 private method를 찾는다. 이 method는 클래스의 public method, private method 모두를 반환한다.
val method = clazz.getDeclaredMethod("secretMethod", String::class.java)
isAccessible 설정을 사용하여 접근 제어를 변경할 수 있다.
method.isAccessible = true
invoke() 메서드를 사용하여 인스턴스를 넘겨주고, 필요한 매개변수를 전달한다.
val result = method.invoke(myClassInstance, "I am hungry.")
전체 예시
class MyClass {
private fun secretMethod(message: String): String {
return "Secret message: $message"
}
}
fun main() {
val myClassInstance = MyClass()
val clazz = MyClass::class.java
val method = clazz.getDeclaredMethod("secretMethod", String::class.java)
method.isAccessible = true
val result = method.invoke(myClassInstance, "I am hungry.")
println(result)
}
Kotlin 자체 reflection API를 사용하여 메타데이터에 접근할 수도 있다. Java reflection을 사용하는 것과 원리는 같다.
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.jvm.isAccessible
class MyClass {
private fun secretMethod(message: String): String {
return "Secret message: $message"
}
}
fun main() {
val myClassInstance = MyClass()
val secretMethod = MyClass::class.declaredFunctions.find { it.name == "secretMethod" }
secretMethod?.isAccessible = true
val result = secretMethod?.call(myClassInstance, "I am hungry.")
println(result)
}
method를 호출할 때 instance를 같이 넘겨줘야한다. 이는 secretMethod 가 static method가 아니라 instance method이기 때문이다. 따라서 객체의 상태에 따라서 method 결과가 달라질 수 있기 때문에 instance가 요구되는 것이다.