Что такое рефлексия и чем она полезна?

avatar
Lehane
1 сентября 2008 в 08:39
940567
23
2309

Что такое отражение и почему оно полезно?

Меня особенно интересует Java, но я предполагаю, что принципы одинаковы для любого языка.

Источник
Nabin
3 ноября 2016 в 05:02
11

Для меня это способ получения имен классов во время выполнения и создания объектов этого класса.

Bill K
4 апреля 2017 в 21:45
80

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

givanse
20 апреля 2018 в 22:34
2

см. также: softwareengineering.stackexchange.com/questions/123956/…

MC Emperor
22 ноября 2018 в 13:02
5

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

Scott
15 декабря 2018 в 00:54
0

Вы можете избежать многих ловушек, связанных с отражением, используя Manifold @Jailbreak. Он обеспечивает прямой типобезопасный доступ к закрытым полям, методам и т. Д. Позвольте компилятору Java безопасно проверить ваш код и позволить Manifold сгенерировать для вас базовый доступ к отражению. Подробнее: manifestold.systems/docs.html#type-safe-reflection

Trap
11 июня 2020 в 01:41
0

@BillK Зачем кому-то использовать отражение вместо статической типизации, если на то не было уважительной причины?

Bill K
12 июня 2020 в 21:03
1

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

Ответы (23)

avatar
Matt Sheppard
1 сентября 2008 в 08:44
1860

Отражение имени используется для описания кода, который может проверять другой код в той же системе (или в самой себе).

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

Итак, чтобы дать вам пример кода этого на Java (представьте, что рассматриваемый объект - foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Один из наиболее распространенных вариантов использования в Java - использование аннотаций. Например, JUnit 4 будет использовать отражение для поиска в ваших классах методов, помеченных аннотацией @Test, а затем будет вызывать их при запуске модульного теста.

Есть несколько хороших примеров отражения, которые помогут вам начать работу по адресу http://docs.oracle.com/javase/tutorial/reflect/index.html

И, наконец, да, концепции очень похожи в других статически типизированных языках, которые поддерживают отражение (например, C #). В языках с динамической типизацией описанный выше вариант использования менее необходим (поскольку компилятор разрешает вызов любого метода для любого объекта, что приводит к сбою во время выполнения, если он не существует), но второй случай поиска методов, которые отмечены или работа определенным образом все еще распространена.

Обновление из комментария:

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

Krsna Chaitanya
23 ноября 2012 в 05:59
36

не могли бы вы объяснить, какое значение имеет этот нулевой параметр в этой строке Method method = foo.getClass (). getMethod ("doSomething", null);

Matt Sheppard
27 ноября 2012 в 01:14
58

Значение null указывает, что методу foo не передаются никакие параметры. Подробнее см. docs.oracle.com/javase/6/docs/api/java/lang/reflect/…, java.lang.Object ...).

bigtunacan
12 марта 2013 в 03:46
836

Просто чтобы прояснить, так как у него так много голосов. Возможность проверять код в системе и видеть типы объектов - это не отражение, а, скорее, самоанализ типа. Отражение - это способность вносить изменения во время выполнения, используя интроспекцию. Различие здесь необходимо, поскольку некоторые языки поддерживают самоанализ, но не поддерживают рефлексию. Одним из таких примеров является C ++.

Bill K
29 июля 2013 в 15:50
45

Мне нравится отражение, но если у вас есть контроль над кодом, то использование отражения, как указано в этом ответе, является нелогичным и, следовательно, злоупотреблением - вам следует использовать Type Introspection (instanceof) и сильные типы. Если есть какой-либо способ, кроме размышлений, что-то сделать, то так и должно быть. Отражение вызывает серьезную боль, потому что вы теряете все преимущества использования статически типизированного языка. Если вам это нужно, вам это нужно, но даже тогда я бы рассмотрел предварительно упакованное решение, такое как Spring или что-то, что полностью инкапсулирует необходимое отражение - IE: пусть у кого-то еще есть головные боли.

geschema
19 июня 2014 в 13:51
3

Разве интроспекция не то же самое, что саморефлексия?

Neon Warge
27 января 2016 в 15:04
0

Я просто понимаю одну вещь, может быть, это то, что я делаю в JavaScript? Я открываю firebugs / chrome. Все это делается во время выполнения. Если это так, вау, это то, что есть.

RestInPeace
29 апреля 2016 в 09:34
6

@bigtunacan Откуда вы взяли эту информацию? Я вижу, что термин «отражение» используется в официальной документации Java от Oracle для описания не только возможности вносить изменения во время выполнения, но и способности видеть тип объекта. Не говоря уже о том, что большинство классов, связанных с так называемым «самоанализом типов» (например: Method, Constructor, Modifier, Field, Member, в основном, очевидно, все, кроме Class) находятся в пределах <25810277 > пакет. Может быть, понятие «отражение» исчерпывающе включает как «самоанализ типа», так и модификацию во время выполнения?

bigtunacan
29 апреля 2016 в 12:53
5

@RestInPeace, это правильное предположение. Рефлексия полагается на самоанализ и, таким образом, включает его как часть. Мой комментарий состоял в том, чтобы уточнить, что отражение позволяет вносить изменения во время выполнения. В ответе приведен пример, показывающий происходящие изменения во время выполнения, но определяющий отражение как просто способность выполнять самоанализ. У этого вопроса очень высокий уровень SEO для размышлений, и я подумал, что важно добавить дополнительные пояснения.

Sebastian Redl
6 февраля 2017 в 09:06
0

C ++ в настоящее время не поддерживает интроспекцию типов каким-либо образом. Это планируется в будущей версии. Некоторые внешние инструменты (такие как moc от Qt) расширяют C ++ за счет возможностей самоанализа типов.

Lucas
24 марта 2017 в 13:51
0

В C # есть динамические и анонимные объекты, например ExpandoObject

Wesos de Queso
30 июля 2017 в 22:47
0

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

idelvall
18 июня 2018 в 06:54
0

@bigtunacan, что неточно, по крайней мере, в мире Java. Отражение - это API для получения и установки этой информации во время выполнения, тогда как интроспекция - это процесс проверки Java-компонентов на основе соглашения об именах методов и отражения coderhelper.com/questions/2044446/…

avatar
Bhushan
27 декабря 2021 в 10:52
1

Я использую отражение для создания объекта на основе имени класса (имя класса в строке) и вызываю метод этого класса

Object obj = Class.forName(config.getClassPath())
                    .getDeclaredConstructor()
                    .newInstance();
Method method = obj.getClass().getMethod("getCustomer", SearchObject.class, ObjectConfig.class,
                HttpServletRequest.class);
method.invoke(obj, searchObject, config, request);

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

avatar
RSG
23 ноября 2020 в 23:01
3

ВАЖНО

Начиная с Java 9 вы больше не можете использовать отражение, если пакет-info.java не открывает модуль для доступа к отражению.

По умолчанию доступ к отражению для всех пакетов в модуле запрещен.

См. Общие сведения о модулях Java 9

avatar
cprn
26 апреля 2019 в 09:34
3

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

Практическим примером использования отражений может быть Java Language Server, написанный на Java, или PHP Language Server, написанный на PHP, и т. Д. Language Server предоставляет такие возможности вашей IDE, как автозаполнение, переход к определению, контекстная справка, типы подсказок и многое другое. Чтобы все имена тегов (слова, которые могут дополняться автоматически) отображали все возможные совпадения при вводе, языковой сервер должен проверять все о классе, включая блоки документов и закрытые члены. Для этого необходимо отражение указанного класса.

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

avatar
BSeitkazin
5 декабря 2018 в 06:35
3

Я хочу ответить на этот вопрос на примере. Прежде всего, проект Hibernate использует Reflection API для генерации операторов CRUD, чтобы преодолеть пропасть между запущенным приложением и хранилищем постоянства. Когда что-то меняется в домене, Hibernate должен знать о них, чтобы сохранять их в хранилище данных, и наоборот.

Альтернативно работает Lombok Project. Он просто вводит код во время компиляции, в результате код вставляется в классы вашего домена. (Думаю, это нормально для геттеров и сеттеров)

Hibernate выбрал reflection, поскольку он оказывает минимальное влияние на процесс сборки приложения.

А из Java 7 у нас есть MethodHandles, который работает как Reflection API. В проектах для работы с логгерами мы просто копируем следующий код:

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

Потому что в этом случае сложно допустить опечатку.

avatar
Mohammed Sarfaraz
9 апреля 2017 в 02:29
9

Судя по названию, оно отражает то, что в нем содержится, например, метод класса и т. Д., Помимо предоставления функции для вызова метода, создающего экземпляр динамически во время выполнения.

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

avatar
roottraveller
22 марта 2017 в 07:27
18

Reflection - это API, который используется для проверки или изменения поведения методов, классов, интерфейсов во время выполнения.

  1. Требуемые классы для отражения представлены в разделе java.lang.reflect package.
  2. Отражение дает нам информацию о классе, к которому принадлежит объект, а также о методах этого класса, которые могут быть выполнены с использованием объекта.
  3. Благодаря отражению мы можем вызывать методы во время выполнения независимо от спецификатора доступа, используемого с ними.

Пакеты java.lang и java.lang.reflect предоставляют классы для отражения Java.

Отражение можно использовать для получения информации о -

  1. Класс Метод getClass() используется для получения имени класса, к которому принадлежит объект.

  2. Конструкторы Метод getConstructors() используется для получения общедоступных конструкторов класса, к которому принадлежит объект.

  3. Методы Метод getMethods() используется для получения общедоступных методов класса, к которому принадлежит объект.

Reflection API в основном используется в:

IDE (интегрированная среда разработки), например Eclipse, MyEclipse, NetBeans и т. Д.
Отладчик, средства тестирования и т. Д.

Преимущества использования отражения:

Функции расширяемости: Приложение может использовать внешние, определяемые пользователем классы, создавая экземпляры объектов расширяемости с использованием их полных имен.

Инструменты отладки и тестирования: Отладчики используют свойство отражения для проверки частных членов в классах.

Отзывы :

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

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

Ссылка: Отражение Java javarevisited.blogspot.in

SantiBailors
20 декабря 2017 в 11:27
4

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

Fernando Gabrieli
1 декабря 2018 в 21:28
0

Таким образом, это позволяет нам (например) проверять имеющиеся у нас классы (есть ли у нас их экземпляры или нет), правильно? Под этим я подразумеваю получение их методов или конструкторов и использование их для создания новых экземпляров / их вызова. Почему мы говорим «изменение поведения программы», если поведение уже существует, но с другим кодом? Почему это называется «отражение»? Спасибо

avatar
saumik gupta
26 апреля 2016 в 22:54
7

Reflection дает вам возможность писать более общий код. Он позволяет вам создавать объект во время выполнения и вызывать его метод во время выполнения. Следовательно, программа может быть сильно параметризована. Это также позволяет интроспектировать объект и класс, чтобы обнаружить его переменные и метод, доступные внешнему миру.

avatar
Ravindra babu
13 февраля 2016 в 12:33
9

Из документации java page

Пакет

java.lang.reflect предоставляет классы и интерфейсы для получения отражающей информации о классах и объектах. Отражение обеспечивает программный доступ к информации о полях, методах и конструкторах загруженных классов, а также использование отраженных полей, методов и конструкторов для работы с их базовыми аналогами в рамках ограничений безопасности.

AccessibleObject позволяет подавить проверки доступа, если необходимый ReflectPermission доступен.

Классы в этом пакете вместе с java.lang.Class поддерживают такие приложения, как отладчики, интерпретаторы, инспекторы объектов, браузеры классов и службы, такие как Object Serialization и JavaBeans, которым требуется доступ к открытым членам целевого объекта. (на основе его класса времени выполнения) или членов, объявленных данным классом

Он включает следующие функции.

  1. Получение объектов класса,
  2. Изучение свойств класса (полей, методов, конструкторов),
  3. Установка и получение значений полей,
  4. Вызов методов,
  5. Создание новых экземпляров объектов.

Посмотрите на эту ссылку документации на методы, предоставляемые Class класс.

Из этой статьи (написанной Деннисом Сосноски, президента Sosnoski Software Solutions, Inc) и этой статьи (pdf, посвященная безопасности):

Я вижу значительные недостатки, чем использование Reflection

Пользователь отражения:

  1. Обеспечивает очень универсальный способ динамического связывания компонентов программы
  2. Это полезно для создания библиотек, которые работают с объектами самыми общими способами

Недостатки отражения:

  1. Отражение происходит намного медленнее, чем прямой код при использовании для доступа к полям и методам.
  2. Он может скрыть, что на самом деле происходит внутри вашего кода
  3. Обход исходного кода может создать проблемы с обслуживанием
  4. Код отражения также более сложен, чем соответствующий прямой код
  5. Это позволяет нарушать ключевые ограничения безопасности Java, такие как как защита доступа к данным и безопасность типа

Общие нарушения:

  1. Загрузка ограниченных классов,
  2. Получение ссылок на конструкторы, методы или поля ограниченного класса,
  3. Создание экземпляров новых объектов, вызов методов, получение или установка значений полей ограниченного класса.

Обратите внимание на этот вопрос SE относительно злоупотребления функцией отражения:

Как прочитать частное поле в Java?

Сводка :

Небезопасное использование его функций из системного кода также может легко привести к компрометации режима безопасности Java l. Так что используйте эту функцию экономно

supercat
1 февраля 2020 в 18:53
0

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

avatar
Marcus Thornton
8 декабря 2015 в 07:02
11

Отражение - это позволить объекту увидеть свой внешний вид. Этот аргумент не имеет ничего общего с размышлениями. Фактически, это способность к самоидентификации.

Само отражение - это слово для таких языков, которые не обладают способностью к самопознанию и самоощущению, как Java и C #. Поскольку они не обладают способностью к самопознанию, когда мы хотим наблюдать, как это выглядит, у нас должна быть другая вещь, чтобы поразмышлять о том, как это выглядит. Превосходные динамические языки, такие как Ruby и Python, могут воспринимать собственное отражение без помощи других людей. Можно сказать, что объект Java не может воспринимать, как он выглядит без зеркала, которое является объектом класса отражения, но объект в Python может воспринимать его без зеркала. Вот почему нам нужно отражение в Java.

AnthonyJClink
30 января 2018 в 16:14
0

type (), isinstance (), callable (), dir () и getattr (). .... это вызовы питонического отражения

avatar
Isuru Jayakantha
6 ноября 2014 в 04:42
19

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

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}
avatar
Desmond Smith
17 октября 2014 в 11:59
91

Использование отражения

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

Функции расширения

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

Недостатки отражения

Отражение - мощное средство, но его нельзя использовать без разбора. Если возможно выполнить операцию без использования отражения, то предпочтительно избегать его использования. При доступе к коду через отражение следует учитывать следующие моменты.

  • Накладные расходы на производительность

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

  • Ограничения безопасности

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

  • Открытие внутренних компонентов

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

источник: API отражения

avatar
catch23
20 сентября 2014 в 22:22
12

Я просто хочу добавить кое-что ко всему, что было перечислено.

С помощью Reflection API вы можете написать универсальный метод toString() для любого объекта.

Это полезно при отладке.

Вот пример:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}
avatar
VeKe
8 сентября 2014 в 09:40
26

Java Reflection довольно мощный и может быть очень полезным. Java Reflection позволяет проверять классы, интерфейсы, поля и методы во время выполнения, , не зная имен классов, методов и т. Д. Во время компиляции. Также возможно создавать экземпляры новых объектов, вызывать методы и получать / устанавливать значения полей с помощью отражения.

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

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

В этом примере объект Class получается из класса MyObject. Используя объект класса, пример получает список методов в этом классе, выполняет итерацию методов и распечатывает их имена.

Здесь подробно объясняется, как все это работает

Изменить : Спустя почти 1 год я редактирую этот ответ, так как, читая об отражении, я получил еще несколько применений Reflection.

  • Spring использует конфигурацию bean-компонентов, например:


<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

Когда контекст Spring обрабатывает этот элемент <bean>, он будет использовать Class.forName (String) с аргументом com.example.Foo для создания экземпляра этого класса.

Затем он снова будет использовать отражение, чтобы получить соответствующий установщик для элемента <property> и установить его значение на указанное значение.

  • Junit использует Reflection специально для тестирования частных / защищенных методов.

Для частных методов,

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Для частных полей:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
avatar
Nikhil Shekhar
8 июля 2013 в 16:12
39

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

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

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

Отражение также позволяет получить доступ к закрытому члену / методам класса:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • Для проверки классов (также известной как интроспекция) вам не нужно импортировать пакет отражения (java.lang.reflect). К метаданным класса можно получить доступ через java.lang.Class.

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

avatar
Ess Kay
6 мая 2013 в 20:16
6

Reflection имеет много использования . То, с чем я более знаком, - это возможность создавать код «на лету».

IE: динамические классы, функции, конструкторы - на основе любых данных (xml / array / sql results / hardcoded / и т. д.)

ThisClark
15 февраля 2017 в 01:53
1

Этот ответ был бы намного лучше, если бы вы привели только один необычный пример сгенерированного кода либо из результата SQL, либо из файла XML и т. Д.

Ess Kay
16 февраля 2017 в 18:41
0

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

Ess Kay
16 февраля 2017 в 18:45
0

По сути, я создал класс, который показывает пользователю отчет. В этом отчете есть такие параметры, как Дата (с по) id или что-то еще. Эта информация хранится в xml. Итак, сначала у нас есть выборка отчетов. На основе выбранного отчета форма получает xml. После получения xml он использует отражение для создания класса с полями на основе отраженных типов. Как только вы переходите к другому отчету, сланец очищается, и новые поля создаются на основе xml. По сути, это динамическая форма, основанная на отражении. Я также использовал другие способы, но этого должно быть достаточно Надежды, которая поможет

avatar
human.js
22 июня 2012 в 15:35
21

Пример :

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

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

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

Atom
22 июня 2015 в 18:42
0

Мне нужно что-то подобное .. Пример мне очень поможет, так как я новичок в концепциях отражения ..

ndm13
11 января 2018 в 02:09
2

Я запутался: нельзя ли использовать instanceof для определения типа объекта во время выполнения?

avatar
pramod
6 февраля 2012 в 05:37
17

Насколько я понимаю:

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

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

Вместо этого, используя отражение, нужно беспокоиться о возможном изменении имени класса.

avatar
Ben Williams
2 сентября 2008 в 16:15
122

Одно из моих любимых применений отражения - это приведенный ниже метод дампа Java. Он принимает любой объект в качестве параметра и использует API отражения Java для вывода имени и значения каждого поля.

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}
Tom
29 апреля 2010 в 13:06
8

На что следует установить Callcount?

Tom
29 апреля 2010 в 13:13
9

Я получил исключение в потоке "AWT-EventQueue-0" java.lang.StackOverflowError, когда я запустил это.

fny
23 ноября 2012 в 06:09
3

@Tom callCount должен быть установлен в ноль. Это значение используется, чтобы определить, сколько вкладок должно предшествовать каждой строке вывода: каждый раз, когда дампу нужно выгрузить «подобъект», вывод будет печататься как вложенный в родительский объект. Этот метод оказывается полезным, когда его оборачивают в другой. Рассмотрим printDump(Object obj){ System.out.println(dump(obj, 0)); }.

Arnaud P
1 июля 2013 в 23:03
1

Ошибка java.lang.StackOverflowError может быть создана в случае циклических ссылок из-за непроверенной рекурсии: buffer.append (dump (value, callCount))

stolsvik
8 октября 2013 в 10:06
4

Не могли бы вы специально выпустить свой код в общественное достояние, пожалуйста?

TheRealChx101
10 декабря 2019 в 16:58
0

@stolsvik Разве в ТАС не говорится, что все, что здесь публикуется, автоматически переходит в общественное достояние или что-то в этом роде? Я искренне задаю вопрос, поэтому не думайте, что я делаю заявление.

Dario Seidl
20 мая 2020 в 20:09
1

@ TheRealChx101 Да, не общественное достояние, но разрешающая лицензия CC BY-SA. coderhelper.com/help/licensing

avatar
toolkit
1 сентября 2008 в 09:30
48

Отражение - это ключевой механизм, позволяющий приложению или фреймворку работать с кодом, который, возможно, еще даже не был написан!

Возьмем, к примеру, типичный файл web.xml. Он будет содержать список элементов сервлета, которые содержат вложенные элементы класса сервлета. Контейнер сервлета обработает файл web.xml и создаст новый экземпляр каждого класса сервлета посредством отражения.

Другой пример - Java API для XML Parsing (JAXP). Если поставщик анализатора XML «подключается» через хорошо известные системные свойства, которые используются для создания новых экземпляров посредством отражения.

И, наконец, наиболее полный пример - Spring, который использует отражение для создания своих bean-компонентов, а также для интенсивного использования прокси

avatar
Liedman
1 сентября 2008 в 08:52
274

Отражение - это способность языка проверять и динамически вызывать классы, методы, атрибуты и т. Д. Во время выполнения.

Например, все объекты в Java имеют метод getClass(), который позволяет вам определять класс объекта, даже если вы не знаете его во время компиляции (например, если вы объявили его как Object) - это может кажутся банальными, но такое отражение невозможно в менее динамичных языках, таких как C++. Более продвинутое использование позволяет вам перечислять и вызывать методы, конструкторы и т. Д.

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

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

Fernando Gabrieli
1 декабря 2018 в 21:40
3

Другими словами, вы можете создать экземпляр из его квалифицированного имени, и компилятор не будет на это жаловаться (потому что, скажем, вы используете только String для имени класса). Затем во время выполнения, если этот класс отсутствует, вы получите исключение. В этом случае вы как бы обошли компилятор. Не могли бы вы дать мне какой-нибудь конкретный пример использования для этого? Я просто не могу представить, когда бы выбрал это.

Liedman
15 января 2019 в 12:25
4

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

Ayxan Haqverdili
10 декабря 2019 в 20:32
1

C++ содержит информацию о типе времени выполнения. RTTI

avatar
Mendelt
1 сентября 2008 в 08:50
42

Не каждый язык поддерживает отражение, но принципы обычно одинаковы для языков, которые его поддерживают.

Отражение - это способность «отразить» структуру вашей программы. Или более конкретно. Для просмотра имеющихся у вас объектов и классов и программного получения информации о методах, полях и интерфейсах, которые они реализуют. Вы также можете просматривать такие вещи, как аннотации.

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

avatar
Jorge Córdoba
1 сентября 2008 в 08:50
16

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

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

В C #, например, вы можете загрузить сборку (.dll) во время выполнения и изучить ее, перемещаясь по классам и выполняя действия в соответствии с тем, что вы нашли. Он также позволяет создавать экземпляр класса во время выполнения, вызывать его метод и т. Д.

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