수색…


소개

리플렉션은 컴파일 타임 대신 런타임에 코드를 검사 할 수있는 언어의 기능입니다.

비고

리플렉션은 런타임에 언어 구성 (클래스 및 함수)을 인트로 스 케 츠 (searrospect)하는 메커니즘입니다.

JVM 플랫폼을 대상으로 할 때 런타임 리플렉션 기능은 별도의 JAR ( kotlin-reflect.jar 됩니다. 이는 런타임 크기를 줄이고 사용되지 않는 기능을 제거하며 JS와 같은 다른 플랫폼을 대상으로 삼을 수 있도록하기 위해 수행됩니다.

클래스 참조하기

어떤 클래스를 나타내는 KClass 객체에 대한 참조를 얻으려면 이중 콜론을 사용하십시오.

val c1 = String::class
val c2 = MyClass::class

함수 참조하기

기능은 Kotlin의 일류 시민입니다. 이중 콜론을 사용하여 참조를 얻은 다음 다른 함수로 전달할 수 있습니다.

fun isPositive(x: Int) = x > 0

val numbers = listOf(-2, -1, 0, 1, 2)
println(numbers.filter(::isPositive)) // [1, 2]

자바 리플렉션과 상호 운용

Kotlin의 KClass 에서 Java의 Class 객체를 얻으려면 .java 확장 속성을 사용하십시오.

val stringKClass: KClass<String> = String::class
val c1: Class<String> = stringKClass.java

val c2: Class<MyClass> = MyClass::class.java

후자의 예제는 중간 KClass 인스턴스를 할당하지 않기 위해 컴파일러에 의해 최적화 될 것이다.

클래스의 모든 속성 값 가져 오기

주어진 Example 클래스는 몇 가지 속성을 가진 BaseExample 클래스를 확장합니다 :

open class BaseExample(val baseField: String)

class Example(val field1: String, val field2: Int, baseField: String): 
    BaseExample(baseField) {
    
    val field3: String
        get() = "Property without backing field"

    val field4 by lazy { "Delegated value" }

    private val privateField: String = "Private value"
}

클래스의 모든 속성을 유지할 수 있습니다.

val example = Example(field1 = "abc", field2 = 1, baseField = "someText")

example::class.memberProperties.forEach { member ->
    println("${member.name} -> ${member.get(example)}")
}

이 코드를 실행하면 예외가 발생합니다. 속성 private val privateField 는 private로 선언되고 member.get(example) 을 호출하면 성공하지 못합니다. 이것을 처리하여 개인 속성을 필터링하는 한 가지 방법. 이를 위해 속성의 Java getter의 가시성 수정자를 확인해야합니다. private val 경우 getter가 존재하지 않으므로 개인 액세스를 취할 수 있습니다.

도우미 기능과 사용법은 다음과 같습니다.

fun isFieldAccessible(property: KProperty1<*, *>): Boolean {
    return property.javaGetter?.modifiers?.let { !Modifier.isPrivate(it) } ?: false
}

val example = Example(field1 = "abc", field2 = 1, baseField = "someText")

example::class.memberProperties.filter { isFieldAccessible(it) }.forEach { member ->
    println("${member.name} -> ${member.get(example)}")
}

또 다른 방법은 리플렉션을 사용하여 개인 속성에 액세스 할 수있게 만드는 것입니다.

example::class.memberProperties.forEach { member ->
    member.isAccessible = true
    println("${member.name} -> ${member.get(example)}")
}

클래스의 모든 속성 값 설정

예를 들어, 샘플 클래스의 모든 문자열 속성을 설정하려고합니다.

class TestClass {
    val readOnlyProperty: String
        get() = "Read only!"

    var readWriteString = "asd"
    var readWriteInt = 23

    var readWriteBackedStringProperty: String = ""
        get() = field + '5'
        set(value) { field = value + '5' }

    var readWriteBackedIntProperty: Int = 0
        get() = field + 1
        set(value) { field = value - 1 }

    var delegatedProperty: Int by TestDelegate()

    private var privateProperty = "This should be private"

    private class TestDelegate {
        private var backingField = 3

        operator fun getValue(thisRef: Any?, prop: KProperty<*>): Int {
            return backingField
        }

        operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Int) {
            backingField += value
        }
    }
}

변경할 수있는 속성을 가져 오려면 모든 속성을 가져 와서 유형별로 변경할 수있는 속성을 필터링합니다. 비공개 속성을 읽으면 런타임 예외가 발생하므로 가시성도 확인해야합니다.

val instance = TestClass()
TestClass::class.memberProperties
        .filter{ prop.visibility == KVisibility.PUBLIC }
        .filterIsInstance<KMutableProperty<*>>()
        .forEach { prop ->
            System.out.println("${prop.name} -> ${prop.get(instance)")
        }

모든 String 속성을 "Our Value" 로 설정하려면 반환 유형별로 추가 필터링을 할 수 있습니다. Kotlin은 Java VM에 근거하고 있으므로, Type Erasure 가 유효 해, List<String> 등의 범용 형을 돌려주는 Properties는 List<Any> . 슬프게도 반사는 황금의 총알이 아니며이를 피할 수있는 합리적인 방법이 없으므로 사용 사례에서주의해야합니다.

val instance = TestClass()
TestClass::class.memberProperties
        .filter{ prop.visibility == KVisibility.PUBLIC }
        // We only want strings
        .filter{ it.returnType.isSubtypeOf(String::class.starProjectedType) }
        .filterIsInstance<KMutableProperty<*>>()
        .forEach { prop ->
            // Instead of printing the property we set it to some value
            prop.setter.call(instance, "Our Value")
        }


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow