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

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

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


person Lehane    schedule 01.09.2008    source источник
comment
Для меня это способ получения имен классов во время выполнения и создания объектов этого класса.   -  person Nabin    schedule 03.11.2016
comment
поскольку это популярный вопрос, я хотел бы указать, что отражение (без аннотаций) должно быть самым последним инструментом, к которому вы должны обратиться при решении проблемы. Я использую его и люблю, но он сводит на нет все преимущества статической типизации Java. Если он вам действительно нужен, изолируйте его на как можно меньшей площади (один метод или один класс). Его более приемлемо использовать в тестах, чем в производственном коде. С аннотациями все должно быть хорошо - главное не указывать имена классов или методов как строки, если вы можете этого избежать.   -  person Bill K    schedule 05.04.2017
comment
см. также: softwareengineering.stackexchange.com/questions/ 123956 /   -  person givanse    schedule 21.04.2018
comment
В дополнение к комментарию @BillK: Отражение очень мощное средство, я бы назвал его волшебством. С большой властью приходит большая ответственность. Используйте его, только если знаете, что делаете.   -  person MC Emperor    schedule 22.11.2018
comment
Вы можете избежать многих ошибок, связанных с отражением, используя Manifold @Jailbreak. Он обеспечивает прямой, типобезопасный доступ к закрытым полям, методам и т. Д. Позвольте компилятору Java безопасно проверить ваш код и позволить Manifold сгенерировать для вас базовый доступ к отражению. Подробнее: manifest.systems/docs.html#type-safe-reflection   -  person Scott    schedule 15.12.2018
comment
@BillK Зачем кому-то использовать отражение вместо статической типизации, если для этого не было уважительной причины?   -  person Trap    schedule 11.06.2020
comment
@Trap Я не знаю, вот почему я рекомендовал это не делать - это действительно раздражает, когда я сталкиваюсь с отражением, когда были доступны другие решения, или отражение, которое не изолировано от очень маленькой, ограниченной и четко задокументированной области код. Но я не могу ответить на вопрос, почему программисты делают то, что они делают.   -  person Bill K    schedule 13.06.2020


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

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

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

person Matt Sheppard    schedule 01.09.2008
comment
не могли бы вы объяснить, какое значение имеет этот нулевой параметр в этой строке Method method = foo.getClass (). getMethod (doSomething, null); - person Krsna Chaitanya; 23.11.2012
comment
Нулевое значение указывает, что методу foo не передаются никакие параметры. См. документы .oracle.com / javase / 6 / docs / api / java / lang / reflection /, java.lang.Object ...) для получения подробной информации. - person Matt Sheppard; 27.11.2012
comment
Просто чтобы прояснить, так как у него так много голосов. Возможность проверять код в системе и видеть типы объектов - это не отражение, а, скорее, самоанализ типа. Отражение - это способность вносить изменения во время выполнения, используя интроспекцию. Различие здесь необходимо, поскольку некоторые языки поддерживают самоанализ, но не поддерживают рефлексию. Одним из таких примеров является C ++. - person bigtunacan; 12.03.2013
comment
Мне нравится отражение, но если у вас есть контроль над кодом, то использование отражения, как указано в этом ответе, является нелогичным и, следовательно, злоупотреблением - вам следует использовать Type Introspection (instanceof) и сильные типы. Если есть какой-либо способ, кроме размышлений, что-то сделать, то так и должно быть. Отражение вызывает серьезную боль, потому что вы теряете все преимущества использования статически типизированного языка. Если вам это нужно, вам это нужно, но даже в этом случае я бы рассмотрел предварительно упакованное решение, такое как Spring или что-то, что полностью инкапсулирует необходимое отражение - IE: пусть у кого-то еще есть головные боли. - person Bill K; 29.07.2013
comment
Разве интроспекция не то же самое, что саморефлексия? - person geschema; 19.06.2014
comment
Я просто понимаю одну вещь, может быть, это то, что я делаю в JavaScript? Я открываю firebugs / chrome. Все это делается во время выполнения. Если это так, вау, это то, что есть. - person Neon Warge; 27.01.2016
comment
@bigtunacan Откуда вы взяли эту информацию? Я вижу, что термин «отражение» используется в официальной документации Java от Oracle для описания не только возможности вносить изменения во время выполнения, но и способности видеть тип объекта. Не говоря уже о том, что большинство так называемых классов, связанных с интроспекцией типов (например: Method, Constructor, Modifier, Field, Member, в основном все, кроме Class) находятся в пакете java.lang.*reflect*. Возможно, отражение концепции всесторонне включает как самоанализ типов, так и модификацию во время выполнения? - person RestInPeace; 29.04.2016
comment
@RestInPeace, это правильное предположение. Рефлексия полагается на самоанализ и, таким образом, включает его как часть. Мой комментарий состоял в том, чтобы уточнить, что отражение позволяет вносить изменения во время выполнения. В ответе приведен пример, показывающий происходящие изменения во время выполнения, но определяющий отражение как просто способность выполнять самоанализ. У этого вопроса очень высокий уровень SEO для размышлений, и я подумал, что важно добавить дополнительные пояснения. - person bigtunacan; 29.04.2016
comment
C ++ в настоящее время не поддерживает интроспекцию типов каким-либо образом. Это планируется в будущей версии. Некоторые внешние инструменты (такие как moc от Qt) расширяют C ++ за счет возможностей самоанализа типов. - person Sebastian Redl; 06.02.2017
comment
В C # есть динамические и анонимные объекты, например ExpandoObject - person Lucas; 24.03.2017
comment
Это бесполезно для редакторов, отличных от Java. Было бы безумием, если бы вы могли изменять атрибуты или методы классов во время выполнения. - person Wesos de Queso; 31.07.2017
comment
@bigtunacan, что неточно, по крайней мере, в мире Java. Отражение - это API для получения и установки этой информации во время выполнения, тогда как интроспекция - это процесс проверки Java-компонентов на основе соглашения об именах методов и отражения stackoverflow.com/questions/2044446/ - person idelvall; 18.06.2018

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

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

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

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

person Liedman    schedule 01.09.2008
comment
Другими словами, вы можете создать экземпляр из его квалифицированного имени, и компилятор не будет на это жаловаться (потому что, скажем, вы используете только String для имени класса). Затем во время выполнения, если этот класс отсутствует, вы получите исключение. В этом случае вы как бы обошли компилятор. Не могли бы вы дать мне какой-нибудь конкретный пример использования для этого? Я просто не могу представить, когда бы выбрал это. - person Fernando Gabrieli; 02.12.2018
comment
@FernandoGabrieli, хотя это правда, что легко создавать ошибки времени выполнения с отражением, также вполне возможно использовать отражение, не рискуя исключениями времени выполнения. Как указано в моем ответе, отражение обычно используется для библиотек или фреймворков, которые явно не могут знать структуру приложения во время компиляции, поскольку они компилируются отдельно от приложения. Любая библиотека, которая использует код по соглашению, вероятно, будет использовать отражение, но не обязательно с использованием магических строк. - person Liedman; 15.01.2019
comment
C++ имеет информацию о типе времени выполнения. RTTI - person Ayxan Haqverdili; 10.12.2019

Одно из моих любимых применений отражения - это приведенный ниже метод дампа 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();
}
person Ben Williams    schedule 02.09.2008
comment
На что следует установить Callcount? - person Tom; 29.04.2010
comment
У меня возникло исключение в потоке AWT-EventQueue-0 java.lang.StackOverflowError, когда я запустил это. - person Tom; 29.04.2010
comment
@Tom callCount следует установить в ноль. Это значение используется, чтобы определить, сколько вкладок должно предшествовать каждой строке вывода: каждый раз, когда дампу необходимо выгрузить подобъект, вывод будет печататься как вложенный в родительский объект. Этот метод оказывается полезным, когда его оборачивают в другой. Рассмотрим printDump(Object obj){ System.out.println(dump(obj, 0)); }. - person fny; 23.11.2012
comment
Ошибка java.lang.StackOverflowError может быть создана в случае циклических ссылок из-за непроверенной рекурсии: buffer.append (dump (value, callCount)) - person Arnaud P; 02.07.2013
comment
Не могли бы вы специально выпустить свой код в общественное достояние, пожалуйста? - person stolsvik; 08.10.2013
comment
@stolsvik Разве в ТАС не говорится, что все, что здесь публикуется, автоматически переходит в общественное достояние или что-то в этом роде? Я искренне задаю вопрос, поэтому не думайте, что я делаю заявление. - person TheRealChx101; 10.12.2019
comment
@ TheRealChx101 Да, не общественное достояние, но разрешающая лицензия CC BY-SA. stackoverflow.com/help/licensing - person Dario Seidl; 20.05.2020

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

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

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

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

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

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

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

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

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

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

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

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

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

person Desmond Smith    schedule 17.10.2014

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

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

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

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

person toolkit    schedule 01.09.2008

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

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

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

person Mendelt    schedule 01.09.2008

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

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, но при чрезмерном использовании он может замедлить работу приложения, поскольку разрешает все типы во время выполнения.

person Nikhil Shekhar    schedule 08.07.2013

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

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

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

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

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

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

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

  • 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);
person VeKe    schedule 08.09.2014

Пример:

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

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

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

person human.js    schedule 22.06.2012
comment
Мне нужно что-то подобное .. Пример мне очень поможет, так как я новичок в концепциях отражения .. - person Atom; 22.06.2015
comment
Я сбит с толку: нельзя ли использовать instanceof для определения типа объекта во время выполнения? - person ndm13; 11.01.2018

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

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

}
person Isuru Jayakantha    schedule 06.11.2014

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

person roottraveller    schedule 22.03.2017
comment
К недостаткам я бы добавил Он нарушает рефакторинг. Для меня это основная причина как можно больше избегать размышлений. - person SantiBailors; 20.12.2017
comment
Так что это позволяет нам (например) проверять имеющиеся у нас классы (есть ли у нас их экземпляры или нет), правильно? Под этим я подразумеваю получение их методов или конструкторов и использование их для создания новых экземпляров / их вызова. Почему мы говорим об изменении поведения программы, если поведение уже существует, но с другим кодом? Почему это называется отражением? Спасибо - person Fernando Gabrieli; 02.12.2018

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

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

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

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

person pramod    schedule 06.02.2012

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

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

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

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

person Jorge Córdoba    schedule 01.09.2008

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

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

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

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

person Marcus Thornton    schedule 08.12.2015
comment
type (), isinstance (), callable (), dir () и getattr (). .... это вызовы питонического отражения - person AnthonyJClink; 30.01.2018

Из страницы документации java.

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

person Ravindra babu    schedule 13.02.2016
comment
В некоторых случаях можно избежать проблем с производительностью Reflection, чтобы класс Woozle проверял другие классы при запуске, чтобы увидеть, какие из них имеют статический RegisterAsWoozleHelper() метод, и вызывать все такие методы, которые он находит, с помощью обратного вызова, который они могут использовать, чтобы сообщить Woozle о сами, избегая необходимости использовать Reflection, например десериализация данных. - person supercat; 01.02.2020

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

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

person Mohammed Sarfaraz    schedule 09.04.2017

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

person saumik gupta    schedule 26.04.2016

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

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

person Ess Kay    schedule 06.05.2013
comment
Этот ответ был бы намного лучше, если бы вы привели только один необычный пример сгенерированного кода либо из результата SQL, либо из файла XML и т. Д. - person ThisClark; 15.02.2017
comment
Без проблем. Я использовал отражение в приложении Windows, которое динамически генерирует интерфейс на основе XML, взятого из базы данных. - person Ess Kay; 16.02.2017
comment
По сути, я создал класс, который показывает пользователю отчет. В этом отчете есть такие параметры, как Дата (с по) id или что-то еще. Эта информация хранится в xml. Итак, сначала у нас есть выборка отчетов. На основе выбранного отчета форма получает xml. После получения xml он использует отражение для создания класса с полями на основе отраженных типов. Как только вы переходите к другому отчету, сланец очищается, и новые поля создаются на основе xml. По сути, это динамическая форма, основанная на отражении. Я также использовал другие способы, но этого должно быть достаточно Надежды, которая поможет - person Ess Kay; 16.02.2017

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

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

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

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

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

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

person BSeitkazin    schedule 05.12.2018

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

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

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

person cprn    schedule 26.04.2019

ВАЖНО

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

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

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

person RSG    schedule 23.11.2020