Я новичок в Java; в процессе обучения я прочитал, что рефлексия используется для вызова классов и методов, а также для того, чтобы узнать, какие методы реализованы или нет.
Когда я должен использовать отражение, и в чем разница между использованием отражения и созданием экземпляров объектов и вызовом методов традиционным способом?
java
reflection
Хамза хаммаш
источник
источник
Ответы:
Отражение намного медленнее, чем просто вызов метода по имени, потому что он должен проверять метаданные в байт-коде, а не просто использовать предварительно скомпилированные адреса и константы.
Отражение также более мощное: вы можете получить определение члена
protected
илиfinal
, снять защиту и манипулировать им, как если бы оно было объявлено изменяемым! Очевидно, что это подрывает многие гарантии, которые язык обычно дает вашим программам, и может быть очень и очень опасным.И это в значительной степени объясняет, когда его использовать. Обычно нет. Если вы хотите вызвать метод, просто вызовите его. Если вы хотите изменить член, просто объявите его изменяемым вместо того, чтобы идти за спиной компиляции.
Одним из полезных применений отражения в реальных условиях является написание фреймворка, который должен взаимодействовать с пользовательскими классами, когда автор фреймворка не знает, какими будут члены (или даже классы). Отражение позволяет им иметь дело с любым классом, не зная об этом заранее. Например, я не думаю, что можно было бы написать сложную аспектно-ориентированную библиотеку без размышлений.
В качестве другого примера, JUnit использовал тривиальный бит отражения: он перечисляет все методы в вашем классе, предполагает, что все вызываемые
testXXX
являются тестовыми методами, и выполняет только те. Но теперь это можно сделать лучше с помощью аннотаций, и на самом деле JUnit 4 вместо этого в основном перешел на аннотации.источник
Когда-то я был таким же, как ты, я мало что знал об отражении - до сих пор не знаю - но я использовал его один раз
У меня был класс с двумя внутренними классами, и у каждого класса было много методов.
Мне нужно было вызывать все методы во внутреннем классе, и вызывать их вручную было бы слишком много работы.
Используя рефлексию, я мог бы вызвать все эти методы всего за 2-3 строки кода вместо числа самих методов.
источник
Я бы сгруппировал использование отражения в три группы:
источник
Reflection позволяет программе работать с кодом, который может отсутствовать, и делать это надежным способом.
«Нормальный код» имеет такие фрагменты,
URLConnection c = null
которые, благодаря своему явному присутствию, заставляют загрузчик классов загрузить класс URLConnection как часть загрузки этого класса, вызывая исключение ClassNotFound и выход.Отражение позволяет вам загружать классы на основе их имен в строковой форме и проверять их на различные свойства (полезно для нескольких версий вне вашего контроля) перед запуском реальных классов, которые зависят от них. Типичным примером является специальный код OS X, используемый для того, чтобы Java-программы выглядели как родные в OS X, которых нет на других платформах.
источник
По сути, отражение означает использование кода вашей программы в качестве данных.
Поэтому, использование отражения может быть хорошей идеей, когда код вашей программы является полезным источником данных. (Но есть компромиссы, поэтому это не всегда может быть хорошей идеей.)
Например, рассмотрим простой класс:
и вы хотите сгенерировать XML из него. Вы можете написать код для генерации XML:
Но это много стандартного кода, и каждый раз, когда вы меняете класс, вы должны обновлять код. Действительно, вы могли бы описать, что делает этот код как
Это алгоритм, и входом алгоритма является класс: нам нужно его имя, а также имена, типы и значения его свойств. Вот где приходит рефлексия: она дает вам доступ к этой информации. Java позволяет вам проверять типы, используя методы
Class
класса.Еще несколько вариантов использования:
Однако полное отражение означает не только просмотр существующего кода (который сам по себе известен как «самоанализ»), но также изменение или генерацию кода. Для этого в Java есть два известных варианта использования: прокси и макеты.
Допустим, у вас есть интерфейс:
и у вас есть реализация, которая делает что-то интересное:
И на самом деле у вас есть вторая реализация:
Теперь вам также нужен вывод журнала; вы просто хотите получить сообщение в журнале всякий раз, когда вызывается метод. Вы можете явно добавить вывод журнала в каждый метод, но это будет раздражать, и вам придется делать это дважды; один раз для каждой реализации. (Так что даже больше, когда вы добавляете больше реализаций.)
Вместо этого вы можете написать прокси:
Опять же, однако, есть повторяющийся шаблон, который может быть описан алгоритмом:
и ввод этого алгоритма - определение интерфейса.
Отражение позволяет вам определить новый класс, используя этот алгоритм. Java позволяет вам делать это, используя методы
java.lang.reflect.Proxy
класса, и есть библиотеки, которые дают вам еще больше возможностей.Так каковы недостатки отражения?
источник
Reflection может автоматически синхронизировать части вашей программы, где раньше вам приходилось вручную обновлять программу, чтобы использовать новые интерфейсы.
источник