Что такое рефлексия java

Рефлексия кода, reflection

Java Reflection API позволяет получать информацию о конструкторах, методах и полях классов и выполнять следующие операции над полями и методами объекта/класса :

Примечание : в тексте используется объект/класс. При работе с объектом (реализацией класса) можно обращаться к полям и методам класса напрямую, если они доступны (не private). При работе с классом можно обращаться к методам класса с использованием Java Reflection API. Но класс необходимо получить из объекта.

Определение свойств класса

В работающем приложении для получения класса необходимо использовать метод forName (String className). Следующий код демонстрирует возможность создания класса без использования и с использованием Reflection :

Метод класса forName(className) часто используется для загрузки JDBC-драйвера.

Методом getName() объекта Class можно получить наименование класса, включающего пакет (package) :

Для получения значения модификатора класса используется метод getModifiers(). Класс java.lang.reflect.Modifier содержит статические методы, возвращающие логическое значения проверки модификатора класса :

Для получения суперкласса рефлексированного объекта (класса) необходимо использовать метод getSuperclass() :

Поскольку в Java отсутствует множественное наследование, то для получения всех предков следует рекурсивно вызвать метод getSuperclass() в цикле, пока не будет достигнут Object, являющийся родителем всех классов. Object не имеет родителей, поэтому вызов его метода getSuperclass() вернет null.

Определение интерфейсов и конструкторов класса

Для получения в режиме run-time списка реализующих классом интерфейсов, необходимо получить Class и использовать его метод getInterfaces(). В следующем примере извлекается список интерфейсов класса ArrayList :

Чтобы IDE (Eclipse) не предупреждала о необходимости определения типа класса

Class is a raw type. References to generic type Class should be parameterized

в коде были использованы generic’и. В консоль выводятся следующие интерфейсы, реализуемые классом ArrayList :

Метод класса getConstructors() позволяет получить массив открытых конструкторов типа java.lang.reflect.Constructor. После этого, можно извлекать информацию о типах параметров конструктора и генерируемых исключениях :

Определение полей класса

Метод getFields() объекта Class возвращает массив открытых полей типа java.lang.reflect.Field, которые могут быть определены не только в данном классе, но также и в его родителях (суперклассе), либо интерфейсах, реализованных классом или его родителями. Класс Field позволяет получить имя поля, тип и модификаторы :

Если известно наименование поля, то можно получить о нем информацию с помощью метода getField() объекта Class.

Методы getField() и getFields() возвращают только открытые члены данных класса. Чтобы получить все поля класса, включая закрытые и защищенные, необходимо использовать методы getDeclaredField() и getDeclaredFields(). Данные методы работают точно так же, как и их аналоги getField() и getFields().

Определение значений полей класса

Класс Field содержит специализированные методы для получения значений примитивных типов: getInt(), getFloat(), getByte() и др. Для установки значения поля, используется метод set(). Для примитивных типов имеются методы setInt(), setFloat(), setByte() и др.

Ниже приведен пример изменения значения закрытого поля класса в режиме run-time.

Определение методов класса

Метод getMethods() объекта Class возвращает массив открытых методов типа java.lang.reflect.Method. Эти методы могут быть определены не только в классе, но также и в его родителях (суперклассе), либо интерфейсах, реализованных классом или его родителями. Класс Method позволяет получить имя метода, тип возвращаемого им значения, типы параметров метода, модификаторы и генерируемые исключения.

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

Пример изменения значения закрытого поля класса

Чтобы изменить значение закрытого (private) поля класса необходимо получить это поле методом getDeclaredField () и вызвать метод setAccessible (true) объекта Field, чтобы открыть доступ к полю. После этого значение закрытого поля можно изменять, если оно не final. В следующем примере определен внутренний класс PrivateFinalFields с набором закрытых полей; одно из полей final. При создании объекта класса поля инициализируются. В методе main примера поочередно в закрытые поля вносятся изменения и свойства объекта выводятся в консоль.

В результате выполнения примера в консоль будут выведены следующие сообщения :

Из приведённого примера видно что поля private можно изменять. Для этого необходимо получить объект типа java.lang.reflect.Field с помощью метода getDeclaredField (), вызвать его метод setAccessible (true) и с помощью метода set () установить требуемое значение поля. Необходимо иметь в виду, что наличие модификатора final в закрытом текстовом поле не вызывает исключений при изменении значений, а само значение поля остаётся прежним, т.е. final поля остаются неизменные. Если не вызвать метод открытия доступа к полю setAccessible (true), то будет вызвано исключение java.lang.IllegalAccessException.

Пример вызова метода, invoke

Java Reflection Api позволяет вызвать метод класса. Рассмотрим пример, в котором определим класс Reflect, включающий поля и методы управления ими. В режиме run-time с помощью метода данного класса будем изменять значения полей и распечатывать их.

Листинг класса Reflect

Класс Reflect включает два закрытых поля (id, name) и методы управления их значениями set/get. Дополнительно в класс включим метод setData, который будем вызывать для изменения значений полей, и метод toString для печати их значений.

Для тестирования объекта типа Reflect с помощью Java Reflection Api создадим класс ReflectionTest. В этот класс включим две процедуры getClassFields и getClassMethods, которые в режиме run-time распечатают всю информацию (описание полей и методов) о классе. Методы получают класс в качестве параметра. В процедурах сначала определяются массивы полей и методы; после этого их параметры распечатываются :

В конструкторе класса ReflectionTest сначала вызываются процедуры определения полей и методов объекта/класса Reflect. После этого вызываются методы изменения значений и печати значений с использованием Reflection API. Для определения метода setData используется массив типов параметров. Вызов метода setData выполняется с передачей ему массива новых значений.

В результате выполнения примера в консоль будут выведены представленные ниже сообщения. Методы setData и toString(), вызываемые с помощью Java Reflection API, вносят измнения в закрытые поля класса и распечатываются их значения.

Скачать пример

Исходный код рассмотренного примера вызова метода invoke с использованием Java Reflection API можно скачать здесь (989 байт).

Источник

Полное руководство по 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. Смотреть картинку Что такое рефлексия 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

Источник

Про Reflect API доступным языком

Что такое рефлексия java. Смотреть фото Что такое рефлексия java. Смотреть картинку Что такое рефлексия java. Картинка про Что такое рефлексия java. Фото Что такое рефлексия java

Всем привет! Недавно услышал, как одни молодые фронтендеры пытались объяснить другим молодым фронтендерам, что такое Reflect в JavaScript. В итоге кто-то сказал, что это такая же штука, как прокси. Ситуация напомнила мне анекдот:

Встречаются два майнера:
— Ты что-нибудь понимаешь в этом?
— Ну объяснить смогу.
— Это понятно, но ты что-нибудь понимаешь в этом?

Вот и с Reflect в JS для кого-то получилась такая же ситуация. Вроде бы что-то говорят, а для чего — непонятно. В итоге я подумал, что стоит об этом рассказать еще раз простым языком с примерами.

Сначала дадим определение, что такое рефлексия в программировании:
Reflection/Reflect API — это API, который предоставляет возможность проводить реверс-инжиниринг классов, интерфейсов, функций, методов и модулей.

Отсюда становится немного понятнее, для чего это API должно использоваться. Reflection API существует в разных языках программирования и, порой, используется для обхода ограничений, накладываемых ЯП. Также он используется для разработки различных вспомогательных утилит и для реализации различных паттернов (таких как Injection) и много чего еще.

Например, Reflection API есть в Java. Он используется для просмотра информации о классах, интерфейсах, методах, полях, конструкторах и аннотациях во время выполнения java программ. К примеру, с помощью Reflection в Java можно использовать ООП паттерн — Public Morozov.

В PHP тоже существует Reflection API, который позволяет не только делать реверс-инжиниринг, но даже позволяет получать doc-блоки комментариев, что используется в различных системах автодокументирования.

В JavaScript Reflect — это встроенный объект, который предоставляет методы для перехватывания JavaScript операций. По сути, это неймспейс (как и Math). Reflect содержит в себе набор функций, которые называются точно так же, как и методы для Proxy.

Некоторые из этих методов — те же, что и соответствующие им методы класса Object или Function. JavaScript растет и превращается в большой и сложный ЯП. В язык приходят различные вещи из других языков. На сегодня Reflect API умеет не так много, как в других ЯП. Тем не менее, есть предложения по расширению, которые еще не вошли в стандарт, но уже используются. Например, Reflection Metadata.

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

Reflect Metadata / Metadata Reflection

Это API создано для получения информации об объектах в рантайме. Это proposal, который пока не является стандартом. Сейчас активно используется полифил. На сегодняшний день активно применяется в Angular. С помощью этого API реализованы Inject и декораторы (анотаторы).

Собственно ради Angular в TypeScript был добавлен расширенный синтаксис декораторов. Одной из интересных особенностей декораторов является возможность получать информацию о типе декорируемого свойства или параметра. Чтобы это заработало, нужно подключить библиотеку reflect-metadata, которая расширяет стандартный объект Reflect и включить опцию emitDecoratorMetadata к конфиге TS. После этого для свойств, которые имеют хотя бы один декоратор, можно вызвать Reflect.getMetadata с ключом «design:type».

В чем различие Reflect от Proxy?

Reflect — это набор полезных методов для работы с объектами, половина которых — это переписанные уже существующие из Object. Сделано это с целью улучшения семантики и наведения порядка, так как Object — это базовый класс, но при этом он содержит очень много методов, которые не должны в нем находиться. Также если вы создаете объект с пустым прототипом, то у вас исчезают методы рефлексии (ниже покажу на примере, что это значит).

Proxy — это класс, который всегда создает новый объект с установленными обработчиками для перехвата доступа. Он позволяет отлавливать любые действия с объектом и модифицировать их. Для реализации различной логики часто применяется Reflect. Ниже на примерах это будет хорошо видно.

Use Cases

Ну и рассмотрим способы применения Reflect API. Некоторые примеры уже давно известны, просто для этих целей мы привыкли использовать методы из класса Object. Но было бы правильнее, по логике, использовать их из пакета Reflect (пакеты — терминология из Java).

Автогенерируемые поля объекта

Мы можем создать объект, в котором поля объекта будут создаваться автоматически во время доступа к ним

Все круто, но такой объект нельзя сериализовать в JSON, получим ошибку. Добавим магический метод сериализации — toJSON

Динамический вызов конструктора

Но хотим уметь динамически вызывать конструктор и создавать объект. Для этого есть Reflect.construct:

Может понадобиться для использования в фабриках (ООП гайз поймут). Пример:

Как такое пишется в 2017 году:

Повторяем поведение jQuery

Следующая строка показывает как можно сделать jQuery в 2 строки:

Удобно, если нужно что-то быстро наваять без зависимостей, а писать длинные нативные конструкции лень. Но в этой реализации есть минус — выбрасывает исключение при работе с null:

Используя Proxy и Reflect можем переписать этот пример:

Теперь при попытке обращения к null свойствам просто будем получать undefined:

Так почему же надо использовать Reflect?

Reflect API более удобен при обработке ошибок. К примеру, всем знакома инструкция:
Object.defineProperty(obj, name, desc)

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

Это позволяет обрабатывать ошибки через условия, а не try-catch. Пример применения Reflect API с обработкой ошибки:

А теперь можно писать так:

Но надо сказать, что есть случаи, когда Reflect также выбрасывает исключения.

Некоторые записи выходят короче

Разница в поведении

Вроде бы все понятно. Делаем выводы, что лучше. Reflect API более логичный.

Работа с объектами с пустым прототипом

Как видите, мы уже не имеем методов рефлексии, например, hasOwnProperty. Поэтомы мы либо пользуемся старым способом, обращаясь к прототипу базового класса, либо обращаемся к Reflect API:

Источник

Заметки на полях о Java Reflection API

Всем привет, меня зовут Евгений Кузьменко, я Android-разработчик и сегодня хочу рассказать о некоторых интересных моментах, с которыми можно столкнуться при работе с Java Reflection (далее просто рефлексия). Хочу обратить ваше внимание, что это не вводная статья, а скорее набор заметок из личного опыта, о которых будет интересно узнать, а еще это полезно для чуточку большего понимания, что же там происходит «под капотом».

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

Теперь по традиции, несколько слов, что же это такое рефлексия и зачем это все вообще надо. Итак, рефлексия — это средство языка программирования Java, необходимое для получения информации о загруженных в память классах, объектах, интерфейсах и последующей работе с ними на этапе выполнения программы. Зачем это надо? Обработка метаинформации о классах, свойствах, методах, параметрах, посредством обработки аннотаций (привет Retrofit); создание прокси-объектов, например для модульного-тестирования; изменение состояния и/или поведения системы посредством модификации свойств объектов; создание экземпляров классов по заданному типу и многое другое.

Работа с классами через Reflection API

Теперь важно понять два момента:

Конкретно для Android-платформы мы также можем получить загрузчик классов другого приложения, используя следующий код:

Следует также вспомнить о вложенных классах и как такие классы загружать. Конечно, первое, что может прийти в голову — написать что-то вроде:

Так вот после выполнения данного кода, в консоль будет выведено следующее:

before
a = 1
b = 5
c = 10
after
a = 2
b = 7
c = 10

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

Proxy и InvocationHandler

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

Kotlin и рефлексия

Более детальную информацию можно получить в официальной документации, а также обратить внимание на описание содержимого пакета kotlin.reflect

Java 7 и новое API для непрямого вызова методов

Теперь две новости — хорошая и плохая. Начну с хорошей — есть альтернативный путь для непрямого вызова методов, не используя рефлексию, а плохая — разработчикам под платформу Андроид этот путь закрыт. Да, конечно, мы можем в проекте использовать switch со строками, ромбовидный оператор и это как бы Java 7, но все мы в душе понимаем, что это лишь «синтаксический обман», а что-то большее спрятано от нас. Вот это именно такой случай с пакетом java.lang.invoke. Android Studio даже будет специально игнорировать этот пакет, чтоб у нас не было соблазна его использовать. Если покопаться в исходниках Android, то можно наткнуться вот на это, а активность по коммитам показывает что работа идет. Вывод — Google работает над этим, ну а время покажет. Ладно, хватит об Андроиде, давайте попробуем разобраться, в чем же основная идея данного механизма вызова методов. Идея в том, что теперь можно получить типизированную ссылку на метод (конструктор, поле) — дескриптор метода. Чтоб было понятнее перейдем к примеру:

Java 9

Выводы

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

Источник

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

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