Вопрос

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

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

Это было полезно?

Решение

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

Например, скажем, у вас есть объект неизвестного типа в 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 / учебник / отражают / index.html

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

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

  

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

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

  

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Обнажение внутренних органов

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Как именно все это работает, объясняется здесь

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

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


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

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

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

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

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

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

Согласно моему пониманию:

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

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

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

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

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

Тот Самый java.lang и java.lang.reflect пакеты предоставляют классы для отражения java.

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

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

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

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

Тот Самый API отражения в основном используется в:

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

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

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

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

Недостатки:

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

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

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

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

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

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

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

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

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

}

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

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

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

С помощью 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 Страница

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

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

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

Он включает в себя следующие функциональные возможности.

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

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

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

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

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

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

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

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

Общие злоупотребления:

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

Взгляните на этот вопрос SE, касающийся злоупотребления функцией отражения:

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

Краткие сведения:

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

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

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

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

  

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

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

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

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

MethodHandles выбрал <=>, поскольку он оказывает минимальное влияние на процесс сборки приложения.

А с Java 7 у нас есть <=>, который работает как <=>. В проектах для работы с регистраторами мы просто копируем и вставляем следующий код:

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top