Для чего нужна рефлексия в java

Практическое применение аннотации в Java на примере создания Telegram-бота

Рефлексия в Java — это специальное API из стандартной библиотеки, которая позволяет получить доступ к информации о программе во время выполнения.

Большинство программ так или иначе пользуются рефлексией в различных его видах, ведь его возможности трудно уместить в одной статье.

Многие ответы заканчиваются на этом, но что более важно, это понимание вообще концепции рефлексии. Мы гонимся за короткими ответами на вопросы, чтобы успешно пройти собеседование, но не понимаем основы — откуда это взялось и что именно понимать под рефлексией.

В этой статье мы коснемся всех этих вопросов применительно к аннотациям и на живом примере увидим как использовать, находить и писать свою.

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

Рефлексия

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

Reflection vs Introspection

Наряду с рефлексией также есть понятие интроспекции. Интроспекция — это способность программы получить данные о типе и других свойствах объекта. Например, это instanceof :

Это очень сильный метод, без чего Java не была бы такой, какая она есть. Тем не менее дальше получения данных он не уходит, и в дело вступает рефлексия.

Некоторые возможности рефлексии

Если говорить конкретнее, то рефлексия — это возможность программы исследовать себя во время выполнения и с помощью неё изменять своё поведение.

Поэтому пример, показанный выше, является не рефлексией, а лишь интроспекцией типа объекта. Но что же тогда является рефлексией? Например, создание класса или вызов метода, но весьма своеобразным способом. Ниже приведу пример.

Представим, что у нас нет никаких знаний о классе, который мы хотим создать, а лишь информация, где он находится. В таком случае мы не можем создать класс очевидным путём:

Воспользуемся рефлексией и создадим экземпляр класса:

Давайте также через рефлексию вызовем его метод:

От теории к практике:

Вопрос #1
Почему в invoke методе в примере сверху мы должны передавать экземпляр объекта?

Далее углубляться я не буду, так как мы уйдём далеко от темы. Вместо этого я оставлю ссылку на статью старшего коллеги Тагира Валеева.

Аннотации

Задумывались ли вы, как оно работает? Если не знаете, то, прежде чем читать дальше, попробуйте догадаться.

Типы аннотаций

Рассмотрим вышеприведённую аннотацию:

@Target — указывает к чему применима аннотация. В данном случае, к методу.

@Retention — длительность жизни аннотации в коде (не в секундах, разумеется).

@interface — является синтаксисом для создания аннотаций.

Если с первым и последним все более менее понятно (подробнее см. @Target в документации), то @Retention давайте разберем сейчас, так как он поможет разделить аннотации на несколько типов, что очень важно понимать.

Эта аннотация может принимать три значения:

Во втором случае аннотация будет доступна и во время выполнения, благодаря чему мы сможем её обработать, например получить все классы, которые имеют данную аннотацию.

В третьем случае аннотация будет удалена компилятором (её не будет в байт-коде). Обычно это бывают аннотации, которые полезны только для компилятора.

SuperCat

Попробуем добавить свою аннотацию (это здорово нам пригодится во время разработки).

Пусть у нас в доме будет два котика: Том и Алекс. Создадим аннотацию для суперкотика:

При этом Тома мы оставим обычным котом (мир несправедлив). Теперь попробуем получить классы, которые были аннотированы данным элементом. Было бы неплохо иметь такой метод у самого класса аннотации:

Но, к сожалению, такого пока метода нет. Тогда как нам найти эти классы?

ClassPath

Это параметр, который указывает на пользовательские классы.

Надеюсь, вы с ними знакомы, а если нет, то спешите изучить это, так как это одна из фундаментальных вещей.

Итак, узнав, где хранятся наши классы, мы сможем их загрузить через ClassLoader и проверить классы на наличие данной аннотации. Сразу приступим к коду:

Не советую использовать это в вашей программе. Код приведён только для ознакомительных целей!

Этот пример показателен, но используется только для учебных целей из-за этого:

Дальше мы узнаем, почему. А пока разберём по строчкам весь код сверху:

Чтобы разобраться, откуда мы берём эти файлы, рассмотрим JAR-архив, который создаётся, когда мы запускаем приложение:

Таким образом, classes — это только наши скомпилированные файлы в виде байт-кода. Тем не менее File — это ещё не загруженный файл, мы только знаем, где они находятся, но мы пока по-прежнему не можем видеть, что находится внутри них.

Поэтому загрузим каждый файл:

Всё, что сделано ранее, было только для того, чтобы вызвать этот метод Class.forName, который загрузит необходимый нам класс. Итак, финальная часть — это получение всех аннотаций, использованных на класс repoClass, а затем проверка, являются ли они аннотацией @SuperCat :

И готово! Теперь, когда у нас есть сам класс, то мы получаем доступ ко всем методам рефлексии.

Рефлексируем

Как и в примере сверху, мы можем просто создать новый экземпляр нашего класса. Но перед этим разберём несколько формальностей.

Итак, обработка обретает финальную форму:

И снова рубрика вопросов:

Подумайте пару минут, а затем сразу разберём ответы:

Ответ #3: Кошкам нужен дом, потому что они являются внутренними классами. Всё в рамках спецификации The Java Language Specification глава 15.9.3.

Подведём итоги и получим: Home.java

Сам он как раз-таки делает всё, что от него нужно. Тем не менее мы его используем неправильно.

Представьте себе, что вы работаете над проектов в котором 1000 и больше классов (всё-таки на Java пишем). И представьте, что вы будете загружать каждый класс, который найдёте в classPath. Сами понимаете, что память и остальные ресурсы JVM не резиновые.

Способы работы с аннотациями

Если бы не было другого способа работать с аннотациями, то использование их в качестве меток класса, как, например, в Spring, было бы весьма и весьма спорным.

Но всё же Spring вроде работает. Неужели из-за них моя программа такая медленная? К сожалению или к счастью, нет. Spring работает исправно (в этом плане), потому что использует несколько иной способ для работы с ними.

Прямо в байт-код

Все (надеюсь) так или иначе имеют представление, что такое байт-код. В нём хранится вся информация о наших классах и их метаданных (в том числе аннотаций).

Так почему бы нам её просто не прочитать (да, из байт-кода)? Но здесь я не буду реализовывать программу для её чтения из байт-кода, так как это заслуживает отдельной статьи. Впрочем, вы сами можете это сделать — это будет отличной практикой, которая закрепит материал статьи.

Для ознакомления с байт-кодом вы можете начать с моей статьи. Там я описываю базовые вещи байт-кода с программой Hello World! Статья будет полезна, даже если вы не собираетесь напрямую работать с байт-кодом. В нем описываются фундаментальные моменты, которые помогут ответить на вопрос: почему именно так?

После этого добро пожаловать на официальную спецификацию JVM. Если вы не хотите разбирать байт-код вручную (по байтам), то посмотрите в сторону таких библиотек, как ASM и Javassist.

Reflections

Reflections — библиотека с WTFPL лицензией, которая позволяет делать с ней всё, что вы захотите. Довольно быстрая библиотека для различной работы с classpath и метаданными. Полезным является то, что она может сохранять информацию о уже некоторых прочитанных данных, что позволяет сэкономить время. Можете покопаться внутри и найти класс Store.

spring-context

Я бы рекомендовал использовать библиотеку Reflections, так как внутри она работает через javassist, что свидетельствует о том, что используется чтение байт-кода, а не его загрузка.

Если ваши классы — это по сути managed beans, то есть находятся в контейнере Spring, то вам незачем повторно их сканировать. Вы просто можете получить доступ к этим бинам из самого контейнера.

Опять же, довольно редко вы должны будете использовать именно такой метод, но как вариант его стоит рассмотреть.
Я писал на нём бота для ВК. Вот репозиторий, с которым вы можете ознакомиться, но писал я его давно, а когда зашёл посмотреть, чтобы вставить ссылку в статью, то увидел, что через VK-Java-SDK я получаю сообщения с неинициализированными полями, хотя раньше всё работало.

Команды в нём представляют из себя вот что:

Примеры кода с аннотацией SuperCat вы можете найти в этом репозитории.

Практическое применение аннотаций в создании Телеграм-бота

Всё это было довольно длинным, но необходимым вступлением для работы с аннотациями. Далее, мы будем реализовывать бота, но цель статьи — это не мануал к его созданию. Это практическое применение аннотаций. Здесь могли быть что угодно: от консольных приложений до этих же самых ботов для вк, телеги и прочего.

Также здесь осознанно не будут выполнятся какие-то сложные проверки. Например, до этого в примерах не было никаких чеков на null или правильной обработки ошибок, не говоря уже об их логировании.

Все это делается для упрощения кода. Поэтому, если вы будете брать код из примеров, то не ленитесь доработать его, так вы лучше его поймете и настроите под свои нужды.

Мы будем использовать библиотеку TelegramBots с MIT лицензией для работы с API телеграма. Вы же можете использовать любую другую. Я выбрал её, потому что она могла работать как «c» (имеет версию со стартёром), так и «без» спринг-бута.

Собственно, я не хочу также усложнять код, добавляя какую-то абстракцию, если хотите, то можете сделать что-то универсальное, но подумайте, стоит ли оно того, поэтому для этой статьи мы часто будем использовать конкретные классы из этих библиотек, привязывая наш код к ним.

Reflections

Первый бот на очереди — это бот, написанный на библиотеке reflections, без Spring. Будем разбирать не всё подряд, а лишь основные моменты, в особенности нас интересует обработка аннотаций. До разбора в статье вы сами можете разобраться в его работе в моём репозитории.

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

Также добавим логгеры. Их мы будем вызвать либо до обработки запроса, либо после, а также комбинировать их:

Но также мы можем добавить параметр, чтобы логгер срабатывал при определённых сообщениях:

Или срабатывал после обработки запроса:

Мы можем делать такое, так как executionTime принимает массив значений. Принцип работы прост, поэтому приступим к обработке этих аннотаций:

По сути, мы просто создаём мапу с именем команды, которую берём из значения value в аннотации. Исходный код здесь.

То же самое делаем с Log, только логгеров с одинаковыми паттернами может быть несколько, поэтому мы чуть меняем нашу структуру данных:

На каждый паттерн приходится несколько логгеров. Остальное всё так же.
Теперь в самом боте нам нужно настроить executionTime и перенаправлять запросы на эти классы:

Лучше всего узнать код самому и посмотреть в репозитории, а ещё лучше открыть его через IDE. Этот репозиторий подходит для начала работы и ознакомления, но в качестве бота он недостаточно хорош.

Спринговый бот

Это приобретает больше смысла при работе с экосистемой спринга:

Но я думаю, что, спринг — это хорошая среда не только для энтерпрайза/веб-приложений. Просто он содержит в себе очень много как официальных, так и пользовательских библиотек для своей экосистемы (под спрингом имеется в виду Spring Boot).

И, самое главное, он позволяет реализовать очень много паттернов различными способами, предоставляемыми контейнером.

Реализация

Что ж, приступим к самому боту.

Поскольку мы пишем на спринговом стеке, то мы можем не создавать свой контейнер команд, а воспользоваться уже существующим в спринге. Их можно не сканировать, а получить из IoC контейнера.

Более самостоятельные разработчики могут сразу приступить к чтению кода.

Здесь же я разберу именно чтение команд, хотя в самом репозитории есть ещё пара интересных моментов, которые вы можете рассмотреть самостоятельно.
Реализация очень похожа на бота через Reflections, поэтому аннотации те же.

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

Подведём итоги

Только вам решать, что лучше подойдёт под вашу задачу. Я разобрал условно три случая для примерно похожих ботов:

Если вы приверженец более чистого подхода с нуля даже без JPA, то посмотрите на этого бота, который работает через JDBC через ВК и Телеграм.

Там вы увидите много записей вида:

Но код имеет двухгодичную давность, так что не советую оттуда брать все паттерны. И вообще я бы не рекомендовал таким заниматься вовсе (работу через JDBC).

Также лично мне не особо нравится работать напрямую с Hibernate. Я уже имел печальный опыт писать DAO и HibernateSessionFactoryUtil (те, кто писал, поймут, о чём я).

Что касается самой статьи, я пытался писать кратко, но достаточно, чтобы, имея в руках только эту статью, вы могли начать разработку. Всё-таки это не глава в книге, а статья на Хабре. Глубже изучить аннотации и вообще рефлексию вы сможете сами, например, создавая того же бота.

Всем удачи! И не забывайте о промокоде HABR, который дает дополнительную скидку 10% к той, что указана на баннере.

Источник

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в javaДля чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в javaДля чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в javaДля чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в javaДля чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в javaДля чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

В этой статье мы узнаем, что такое Рефлексия (Reflection) в Java, зачем она нам нужна, каковы её минусы, а также научимся базовой работе с ней.

Для начала нам необходимо будет разобрать немного теории.

Что такое Рефлексия?

Минусы Рефлексии

Как и у всего в этом мире, у Рефлексии есть свои недостатки:

Что такое Класс класса, у кого он есть?

В Java есть специальный класс по имени Class, да-да, именно Class. Поэтому его и называют классом класса. С помощью него осуществляется работа с рефлексией, он и является входной точкой в мир рефлексии.

Class есть у :

В общем, Class есть у всех объектов в Java.

А теперь перейдем к практике, для этого нам понадобится класс Car

Источник

Полное руководство по Java Reflection API. Рефлексия на примерах

В этой статье мы познакомимся со всеми элементами и функциональными возможностями Java Reflection API.

Рефлексия в Java — это механизм, с помощью которого можно вносить изменения и получать информацию о классах, интерфейсах, полях и методах во время выполнения, при этом не зная имен этих классов, методов и полей. Кроме того, Reflection API дает возможность создавать новые экземпляры классов, вызывать методы, а также получать или устанавливать значения полей.

Начинающие Java-программисты часто путают рефлексию с интроспекцией. Интроспекция — проверка кода и возможность видеть типы объектов во время выполнения. Рефлексия дает возможность вносить изменения во время выполнения программы путем использования интроспекции. Здесь важно понимать различие, поскольку некоторые языки поддерживают интроспекцию, но не поддерживают рефлексию, например, C++.

В этом руководстве мы рассмотрим не только базовые, но и более продвинутые возможности Reflection API.

Java Reflection API

Рефлексия — мощная концепция, которая лежит в основе большинства современных Java/Java EE фреймворков и библиотек. Например, для Java классическими примерами являются:

Список можно продолжать бесконечно: от веб-контейнеров до решения задач объектно-реляционного отображения (ORM). Их всех объединяет одно: они используют Java рефлексию, потому что не имеют доступа и представления к определенных пользователем классах, методах, интерфейсах и т.д.

Ограничения при работе с рефлексией в Java

Почему мы не должны использовать рефлексию в обычном программировании, когда уже есть доступ к интерфейсам и классам. Причин несколько:

Источник

Рефлексия Java-кода с помощью библиотеки Java Reflection API

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

Рефлексия Java — это процесс, при котором данные кода программы исследуются прямо во время ее работы. Также этот процесс позволяет изменять и исследовать классы, интерфейсы, поля, методы программы, не зная их имен. Не нужно путать рефлексию с интроспекцией! Это часто делают молодые Java-разработчики.

Рефлексия Java

Рефлексия Java осуществляется при помощи библиотеки Java Reflection API. Рефлексия помогает осуществить следующее:

выявить данные о модификации классов, полей, методов, констант, конструкторов, суперклассов;

разработать образец класса, при это м имя этого класса остается неизвестным до старта работы программы;

определить и изменить значение свойств объектов или классов;

вызвать методы объектов или классов.

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

Может возникнуть резонный вопрос : «А зачем нам нужна рефлексия Java? ». То есть зачем нам вмешиваться в рабочий процесс программы и изменять там что-то? Ответ будет простой, но в то же время и неопределенный: рефлексия повышает гибкость вашего приложения и расширяет возможности его тонкой настройки. Для чего это нужно — решать только вам. микрозайм без проверок

Недостатки рефлексии Java

С достоинствами рефлексии Java вроде ясно — она добавляет гибкость в настройке вашего собственного Java-приложения. Но при этом рефлексия имеет ряд недостатков, о которых нужно знать перед ее применением:

Уменьшается производительность. Рефлексия работает в динамическом режиме и поэтому постоянно «сканирует» классы для загрузки нужного вам. Это очень сильно снижает скорость работы всего приложения.

Усложняется поддержка. После рефлексии нам достается довольно трудный для понимания код, который сложно читать и отлаживать.

Где применяется рефлексия Java на практике?

Добрый день, %username%!

Спешим вам напомнить, что вы не вернули в срок большую сумму денежных средств в размере %amount% рублей! Нужно вернуть!

С пониманием, Коллекторское агентство «Розовая пони»

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.

Источник

В каких случаях на практике применять рефлексию, аннотации?

У меня, как у новичка, возникает резонный вопрос, зачем мне эту информацию узнавать, если классы, методы, поля и т.д. я пишу сам и всё про них знаю?

Понимаю, что используется рефлексия не для своих классов и т.д., но не могу найти реальный пример, который был бы понятен новичку: в какой ситуации я столкнусь с тем, что не буду знать имя класса, метода и т.д.?

То же самое с аннотациями: «. средство, позволяющее встраивать справочную информацию в исходные файлы. «. Ну встрою я её, ну а профит какой, что я в итоге с помощью этого получу? Какие плюшки для разработчика появятся при наличии аннотаций? Как они способны облегчить жизнь?

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

Для чего нужна рефлексия в java. Смотреть фото Для чего нужна рефлексия в java. Смотреть картинку Для чего нужна рефлексия в java. Картинка про Для чего нужна рефлексия в java. Фото Для чего нужна рефлексия в java

2 ответа 2

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

И, конечно, когда они используются, то применяются не к конкретным классам, а с запасом, даже к тем классам, которые вы напишете в будущем. Часто их используют в библиотечном коде, который будет бродить между проектами и, соответственно, о классах тех проектов вообще не знать ничего.

Несколько конкретных примеров:

Аннотации Hibernate

Hibernate — это ORM, то есть библиотека для удобного отображения баз данных на объектный код. Часто в базе и в Java-коде применяются разные соглашения об именовании. Для того, чтобы Hibernate понимал, какое поле куда копировать, применяют аннотации. Для таблицы:

Можно применить аннотации:

Компилятор Java

AndroidAnnotations

Проект http://androidannotations.org/ позволяет значительно упростить разработку кода для Android, реализовав частые задачи, и обернув их в аннотации. Это как раз хороший пример библиотечного кода, который будет работать в незнакомых проектах. Естественно, для реализации этого кода активно применяется рефлексия. Пример «до аннотаций» и «после аннотаций» приведён прямо на главной странице по ссылке выше.

Аспектно-ориентированное программирование

Про него много писать не буду, поскольку тема очень большая и новичку может быть не сильно нужная. Но в целом АОП как раз об этом. Например, вы можете написать свои классы, а потом озаботится проверкой прав доступа, навроде администратор может удалять записи, а обычный пользователь — нет.

Рефлексия без аннотаций

Рефлексия применяется ещё чаще, например, в разного рода шаблонизаторах и мапперах. Шаблонизаторы позволяют вам использовать шаблоны писем, например, как этот:

Затем вы передаете шаблонизатору класс с полями username и amount и он самостоятельно сформирует текст письма. Такую задачу без рефлексии не сделать.

Заключение

В целом, рефлексия и аннотации позволяют избавиться от так называемого monkey coding, то есть от монотонного низкоуровнего кодирования.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *