#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 }