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

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

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

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

Nabin 03.11.2016 08:02

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

Bill K 05.04.2017 00:45

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

givanse 21.04.2018 01:34

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

MC Emperor 22.11.2018 16:02

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

Scott 15.12.2018 03:54

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

Trap 11.06.2020 04:41

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

Bill K 13.06.2020 00:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2 238
7
920 127
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Ответ принят как подходящий

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

Например, предположим, что у вас есть объект неизвестного типа в 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#). В языках с динамической типизацией описанный выше вариант использования менее необходим (поскольку компилятор разрешит вызов любого метода для любого объекта, что приведет к сбою во время выполнения, если он не существует), но второй случай поиска методов, которые отмечены или работа определенным образом все еще распространена.

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

The ability to inspect the code in the system and see object types is not reflection, but rather Type Introspection. Reflection is then the ability to make modifications at runtime by making use of introspection. The distinction is necessary here as some languages support introspection, but do not support reflection. One such example is C++

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

Krsna Chaitanya 23.11.2012 09:59

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

Matt Sheppard 27.11.2012 05:14

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

bigtunacan 12.03.2013 07:46

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

Bill K 29.07.2013 19:50

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

geschema 19.06.2014 17:51

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

Neon Warge 27.01.2016 18:04

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

RestInPeace 29.04.2016 12:34

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

bigtunacan 29.04.2016 15:53

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

Sebastian Redl 06.02.2017 12:06

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

Lucas 24.03.2017 16:51

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

Wesos de Queso 31.07.2017 01:47

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

idelvall 18.06.2018 09:54

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

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

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

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

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

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

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

Reflection is a language's ability to inspect and dynamically call classes, methods, attributes, etc. at runtime.

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

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

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

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

Fernando Gabrieli 02.12.2018 00:40

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

Liedman 15.01.2019 15:25

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

Ayxan Haqverdili 10.12.2019 23:32

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

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

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

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

Одно из моих любимых применений отражения - это приведенный ниже метод дампа 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();
}

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

Tom 29.04.2010 17:06

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

Tom 29.04.2010 17:13

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

fny 23.11.2012 10:09

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

Arnaud P 02.07.2013 03:03

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

stolsvik 08.10.2013 14:06

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

TheRealChx101 10.12.2019 19:58

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

Dario Seidl 20.05.2020 23:09

В соответствии с моим пониманием:

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

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

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

Пример:

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

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

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

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

Atom 22.06.2015 21:42

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

ndm13 11.01.2018 05:09

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

IE: dynamic classes, functions, constructors - based on any data (xml/array/sql results/hardcoded/etc..)

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

ThisClark 15.02.2017 04:53

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

Ess Kay 16.02.2017 21:41

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

Ess Kay 16.02.2017 21:45

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

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.

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

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

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

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

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

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

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

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

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


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

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

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

  • 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);

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

С помощью 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;
   }    
}

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

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

Возможности расширяемости

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

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

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

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

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

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

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

  • Открытие внутренних органов

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

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

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

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);
    }

}

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

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

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

AnthonyJClink 30.01.2018 19:14

Из документации Java страница

java.lang.reflect package provides classes and interfaces for obtaining reflective information about classes and objects. Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

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. Так что используйте эту функцию экономно

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

supercat 01.02.2020 21:53

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

Отражение - это 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 и т. д.
Отладчик, средства тестирования и т. д.

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

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

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

Недостатки:

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

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

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

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

SantiBailors 20.12.2017 14:27

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

Fernando Gabrieli 02.12.2018 00:28

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

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

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

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

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

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

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

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

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

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

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

ВАЖНЫЙ

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

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

См. Понимание модулей Java 9

Другие вопросы по теме