Как получить методы из KClass в Kotlin

#java #android #class #kotlin #reflection

#java #Android #класс #kotlin #отражение

Вопрос:

В java, когда у меня есть экземпляр Class<>, у меня есть GetMethod, который возвращает метод, и он очень прост в использовании. Как я вижу, Kotlin усложняет жизнь, потому что такого метода не существует. есть ли хороший способ получить конкретный метод, кроме превращения KClass в Class, а затем использовать его точно так же, как в Java?

Комментарии:

1. Вам нужно получить метод по имени строки? В противном случае вы можете просто использовать ::methodName .

2. В противном случае вы можете получить KCallable с помощью class.members.single { it.name == "theFunctionName" }

3. да, мне нужно по имени. Кстати, ::methodName не работает, когда я попробовал следующее: val str:String =»dsasa» var kclass : KClass<out String> = str::class str.toUpperCase()

4. Я не совсем понимаю, что вы пытались, вероятно, из-за форматирования комментариев, но вы можете отредактировать его в вопросе, если хотите спросить об этом тоже.

5. @Tenfour04, я все понимаю! Спасибо! вы должны написать официальный ответ, чтобы я мог вознаградить вас 🙂 Вы являетесь мастером лямбда-выражения. Всего два небольших и важных вопроса: 1. Привязывает ли этот синтаксис экземпляр к функции? 2. Включает ли коллекция members методы сопутствующего объекта?

Ответ №1:

Предположим, у вас есть этот класс:

 class Test {
    fun sayHello() = println("Hello world")

    companion object {
        fun foo() = println("foo")
    }
}
 

Это дает вам экземпляр функции, который вы можете вызывать с invoke() помощью (который является операторной функцией, поэтому вы можете просто использовать круглые скобки, как с любой другой функцией. Если вы получаете функцию, используя имя класса, подобное этому, она не привязана к экземпляру. Таким образом, вы передаете экземпляр в качестве первого параметра при вызове. (Если sayHello() бы были дополнительные параметры, они просто следовали бы за первым параметром Test .)

 val sayHelloFunction = Test::sayHello
val test = Test()
helloWorldFunction(test) // same as calling test.sayHello()
 

Вы также можете получить ссылку на функцию, которая привязана к экземпляру, подобному этому. Он не может быть вызван в других экземплярах Test.

 val test = Test()
val sayHelloFunction = test::sayHello
helloWorldFunction() // same as calling test.sayHello()
 

Описанный выше метод не требует библиотеки отражения Kotlin.

Чтобы получить элемент по имени строки, не существует конкретной функции, подобной Java getMethod , поэтому вам нужно выбрать ее из списка членов, которые являются KCallable . У KCallable нет operator fun invoke , поэтому вы должны использовать call его для вызова или приведения к определенному типу функции (в данном случае это было бы (Test) -> Unit ).

 val sayHelloCallable = Test::class.members.single { it.name == "sayHello" }
val test = Test()
sayHelloCallable.call(test) // same as calling test.sayHello()
 

Здесь не перечислены члены сопутствующего объекта, поскольку это другой класс. Для этого вам нужно будет получить класс компаньона:

 Test.Companion::class.members.single { it.name == "foo" }
 

Я не знаю, есть ли способ получить версию, связанную с экземпляром, по имени.

Что касается того, почему для KClass нет удобной getMethod функции, я могу только догадываться, что, поскольку классы Kotlin имеют так много разных типов членов (свойства, функции, делегаты, вспомогательные поля), возможно, они хотят ограничить раздувание API и считают, что встроенные функции фильтрации, подобные single адекватным.

Комментарии:

1. большое спасибо. Отличное объяснение. Может быть, вы можете объяснить, почему говорят: «Вышеуказанный метод не требует библиотеки отражения Kotlin «. Почему в первом примере используется отражение, а во втором — нет?

2. Менее часто используемые функции отражения находятся в этой библиотеке для уменьшения размера скомпилированных приложений Kotlin.

3. ДА. :: всегда можно использовать без библиотеки отражения.

4. Я имею в виду, что это всего лишь часть языка, а не класс, которому нужна функция вызова. Примерно так же устроены примитивы в Java.

5. Вы можете поместить все, что хотите, в single лямбда-выражение, чтобы выбрать то, что вы хотите, например .single { it.name == "foo" amp;amp; it.parameters.size == 2 }

Ответ №2:

Чтобы получить a Class из a KClass , вы просто вызываете .java его (и .kotlin идете другим путем).