поля - рефлексия java




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

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

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

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

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

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

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


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

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

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

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

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

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

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

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


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

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

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

  • Junit использует Reflection специально для тестирования Private / Protected методов.

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

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

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

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

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


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

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

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

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


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

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

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


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

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

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


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


По моему пониманию:

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

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

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


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

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


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

С API Reflection вы можете написать универсальный метод 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;
   }    
}

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

Недостатки:

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

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

Ссылка: Java Reflection javarevisited.blogspot.in


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

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

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

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

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

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

  • Производительность

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

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

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

  • Воздействие внутренних

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

источник: API Reflection





terminology