И вот я восстав из пепла сегодня вам расскажу про довольно прикольную тему которая недавно всплыла. Ко мне пришли с вот таким вопросом:
Относится ли is/as/java instanceOf к рефлексии?
Первое что я подумал, что вероятнее всего у человека, который оставляет подобные комменты в пул реквесте кресло имеет форму бутылки. Однако, я вспомнил что я же блогер и должен заниматься ликбезом. Итак, рассмотрим что является рефлексией, а что нет.
Все боятся рефлексии, потому как она медленная, могут быть проблемы с обфускацией, и проще закосячить при рефакторинге. И мы порой настолько ее боимся, что пытаемся ее увидеть даже там где ее нет. А там где она есть, мы ее в упор не замечаем. Вы же в курсе что все вызовы методов retrofit проходят через proxy класс, который явно накладывает издержки?
Для начала нужно понять что есть понятие “рефлексия” и понятие “интроспекция”. Рефлексия – способность программы анализировать свое состояние и менять свою структуру и состояние во время выполнения. Интроспекция – способность программы анализировать типы данных и свойства объектов во время выполнения. Или упрощая: рефлексия – readwrite, интроспекция – read only.
Теперь возвращаясь к вопросу,
is/as/java instanceOf – это интроспекция, тут никаких издержек нет, это стандартный механизм языка. Думать что это рефлексия это какой-то абсурд, потому какие точно такие же конструкции есть в C++. А в C++ нет такой вещи как рефлексии (вообще есть, но это костыль и вообще не тоже самое что в языках с GC), потому как в нем нет runtime. Рефлексия это когда кто-то пытается создать объект не через конструктор или например вызвать private метод снаружи, вот тогда уже стоит напрягаться.Тут можно было закончить, но фишка в чем, что в kotlin с точки зрения дизайна работы с рефлексией немного проебались. Потому как синтаксически доступ к рефлексии совпадает с method reference, что также многих путает и заставляет видеть рефлексию там, где ее нет.
Вот пример, два вызова
number::inc,
fun someFn(block: () -> Int) {
println(block())
}
fun main() {
val number = 4
someFn(number::inc)
println(number::inc)
}
В первом случае это просто синтаксическая конструкция абсолютно полностью аналогична
someFn{number.inc()}, во втором же случае, мы именно что обращаемся к ссылке на метод, т.е именно что задействуем рефлексию. Важно понимать, что некоторые вещи в kotlin работают по разному в зависимости от контекста. Ну и что нужно делать, чтобы не заниматься охотой на ведьм? Первое – лакмусовой бумажкой при работе с kotlin является тот момент, когда студия вам предлагает ипортировать пакет kotlin reflection, в этот момент крепко задумайтесь. Второе – в любой непонятной ситуации пользуйтесь инструментом для чтения байт кода, который позволяет увидить как это выглядит в Java, в подавляющем числе случаев, любые вопросы тут же отпадут.