본문 바로가기

Kotlin

Reflection #2

생성자에 대한 정보

@Test
fun `생성자에 대한 정보 얻기`() {
    val clazz = Class.forName("java.lang.String")
    val ctorlist = clazz.declaredConstructors

    ctorlist.forEach {ct ->
        println("생성자 이름 = ${ct.name}")
        println("정의된 클래스 이름 = ${ct.declaringClass}")

        val pvec = ct.parameterTypes
        pvec.forEachIndexed {index, param ->
            println("인자 $index = $param")
        }

        val evec = ct.exceptionTypes
        evec.forEachIndexed { index, exception ->
            println("익셉션 $index = $exception")
        }
    }
}

클래스 필드 정보

@Test
fun `클래스 필드 찾기`() {
    val cls = Class.forName("java.lang.String")
    val fieldList = cls.declaredFields

    fieldList.forEach {
        println("필드명 ${it.name}")
        println("정의된 클래스 ${it.declaringClass}")
        println("필드타입 ${it.type}")
        println("접근제어자 ${Modifier.toString(it.modifiers)}")
    }
}

메소드 이름으로 실행

@Test
fun `메소드 이름으로 실행`() {
    val cls = Class.forName("java.lang.String")
    val data = "Hello World"

    val lengthMethod = cls.getMethod("length") // length() 메소드 찾기
    val length = lengthMethod.invoke(data) // data.length()

    assertEquals(11, length)

    // 두개의 Int 타입이 있는 substring 메소드
    val substringMethod = cls.getMethod("substring", Integer.TYPE, Integer.TYPE)
    val subStr = substringMethod.invoke(data, 0, 5)
    assertEquals("Hello", subStr)
}

private한 메소드도 invoke 할 수 있다

class A {
    private fun show() {
        println("가나다")
    }
}

@Test
fun `private 메소드 invoke`() {
    val a = A()

    with(a.javaClass.getDeclaredMethod("show")) {
        isAccessible = true
        invoke(a)
    }
}

getMethod()는 public한 메소드를 가져온다
getDeclaredMethod()는 private한 메소드를 포함한 클래스에 선언된 모든 메소드를 가져온다

리플렉션으로 오브젝트 생성

class Person(val name: String, val age: Int) {

    fun sayMyName() {
        println("이름 = $name, 나이 = $age")
    }
}

@Test
fun `오브젝트 생성`() {
    val personClass = Class.forName("jo.xyz.appstudy.Person")
    val personConstructor = personClass.getConstructor(String::class.java, Integer.TYPE)
    val person = personConstructor.newInstance("seongjun", 33) as Person
    person.sayMyName()
}

필드의 값 변경

@Test
fun `필드의 값 변경`() {
    val cls = Class.forName("jo.xyz.appstudy.Person")
    val ageField = cls.getDeclaredField("age")
    ageField.isAccessible = true

    val person = Person("seongjun", 33)
    assertEquals(33, person.age)

    ageField.setInt(person, 23)
    assertEquals(23, person.age)
}

실제 제가 사용했던 코드

private fun setDividerColor(vararg pickers: NumberPicker) {
    try {
        val selectionDivider = NumberPicker::class.java.getDeclaredField("mSelectionDivider")
        selectionDivider.isAccessible = true

        for (picker in pickers) {
            selectionDivider.set(picker, dividerColor)
        }
    } catch (e: NoSuchFieldException) {
    } catch (e: IllegalAccessException) {
    }
}

번외

@Test
fun `궁금하다 알아보자`() {
    val intClass1 = Int::class.java
    val intClass2 = Integer.TYPE
    val intClass3 = Int::class
    val intClass4 = Int.javaClass

    println("intClass1 = $intClass1") // int
    println("intClass2 = $intClass2") // int
    println("intClass3 = $intClass3") // class kotlin.Int
    println("intClass4 = $intClass4") // class kotlin.jvm.internal.IntCompanionObject

    assertTrue(Integer.TYPE == Int::class.java)

    val i = 0

    println("i.javaClass = ${i.javaClass}") // int
    println("i::class.java = ${i::class.java}") // int
    println("i::class = ${i::class}") // class kotlin.Int

    assertTrue(Int.javaClass != i.javaClass)
    assertTrue(Int::class == i::class)
    assertTrue(Int::class.java == i::class.java)
}





출처

'Kotlin' 카테고리의 다른 글

Reflection #1  (0) 2020.06.29