Java: Какие сценарии требуют использования отражения? - PullRequest
10 голосов
/ 10 февраля 2012

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

так можно ли это сделать для сторонних классов, созданных java-библиотекой, для которых нет исходного кода / можно ли использовать отражение для изменения экземпляров классов во время выполнения?

в каких других сценариях обычно используется отражение?

Я пытаюсь понять, как отражение может быть применимо.

Ответы [ 7 ]

13 голосов
/ 10 февраля 2012

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

  1. Удаленный вызов процедуры - обрабатывать часть сообщения, полученного черезсеть как имя метода.
  2. Сериализация и десериализация - преобразование имен полей в строку, чтобы вы могли записать поля объекта в поток, а затем преобразовать его обратно в объект.
  3. Object-реляционные отображения - поддерживают связь между полями в объекте и столбцами в базе данных.
  4. Интерфейсы с динамически типизированными языками сценариев - превращают строковое значение, создаваемое языком сценариев, в ссылку на поле или метод наобъект.

Он также может использоваться для эмуляции языковых функций языка.Рассмотрим командную строку java com.example.MyClass, которая превращает строку в имя класса.Это не требует отражения, потому что исполняемый файл java может превратить файл .class в код, но без отражения он не сможет записать java com.example.Wrapper com.example.MyClass, где Wrapper делегирует свой аргумент, как в:

class Wrapper {
  public static void main(String... argv) throws Exception {
    // Do some initialization or other work.
    Class<?> delegate = Class.forName(argv[0]);
    Method main = delegate.getMethod("main", String[].class);
    main.apply(null, Arrays.asList(argv).subList(1, argv.length).toArray(argv));
  }
}
4 голосов
/ 10 февраля 2012

Отражение используется, когда необходимо попасть в другой classes in deeper level.Так что в большинстве случаев эти разработчики имеют поведение контейнера.Например, внедрение зависимостей в основном выполняется с использованием отражения.Если вам в качестве примера для этого нужен фреймворк, Spring выполняет задания внедрения зависимостей с помощью reflection API.

. Вы также найдете отражения, используемые за кулисами в большом количестве областей.Например, если вы использовали JAXB, то большая часть маршаллинга / демаршаллинга XML будет выполняться с использованием отражений.Использование аннотаций в вашем коде часто приводит к тому, что за кулисами используются отражения.При выполнении модульного тестирования, особенно при имитации классов и / или методов, часто используется много кода отражений.

3 голосов
/ 10 февраля 2012

В другом случае разрабатываются IDE, такие как eclipse / netbeans и т. Д., Чтобы определить, какие методы в абстрактном классе необходимо реализовать дочерним классом, и автоматически написать для вас вызовы отсутствующих методов (один пример).

2 голосов
/ 10 февраля 2012

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

0 голосов
/ 12 мая 2017

Вот несколько случаев использования отражения в

public class Main {

    public static void main(String[] args) {

        displayProperties(Stage.class);
    }

    public static void displayProperties(Class class) {
        boolean hasParam = false;
        boolean hasReturn = false;
        ArrayList<Method> propMethods = new ArrayList<>();
        Method[] methods = clazz.getMethods();
        for (Method m: methods) {

            Parameter[] paraType = m.getParameters();
            if(m.getParameterCount()<2) {
                if ((m.getReturnType() == void.class && paraType.length == 1) || (m.getReturnType() != void.class && paraType.length == 0)) {
                    //Get the properties alone
                    propMethods.add(m);
                }
            }

        }
        for (int i = 0; i < propMethods.size(); i++) {

            if (propMethods.get(i).getName().startsWith("get") || propMethods.get(i).getName().startsWith("set")) {

                System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName().substring(3)+"( "+propMethods.get(i).getReturnType().getTypeName()+" )");
            } else
                System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName() + "( "+propMethods.get(i).getReturnType().getTypeName()+" )");
        }

    }

    public static String readWrite(Method method, ArrayList<Method> propMeths) {

        ArrayList<Method> temp;
        temp = propMeths;

        boolean readIn = false;
        boolean writeIn = false;
        String onlyName = method.getName().substring(3);

        for (int i = 0; i < temp.size(); i++) {
            //use the substring--

            if (temp.get(i).getName().startsWith("get") && temp.get(i).getName().endsWith(onlyName)) {
                readIn = true;
            }
            if (temp.get(i).getName().startsWith("set") && temp.get(i).getName().endsWith(onlyName)) {

                writeIn = true;
            }
        }

        if (readIn == true && writeIn == true)
            return "rw ";
        else if (readIn == true && writeIn == false)
            return "r ";
        else
            return "w ";
    }
}

Другой случай с классом String

public static void main(String[] args) 
    {
        displayProperties(String.class);
    }

    public static void displayProperties(Class class){
        clazz.getDeclaredFields();

        Method[] methods = clazz.getDeclaredMethods();

        for(int ii = 0; ii<methods.length; ii++){
            System.out.println("Method Name: "+methods[ii].getName());
            System.out.println("Method Type: "+methods[ii].getReturnType());
            System.out.println("Method Pa: "+methods[ii].getParameterCount());
            System.out.println("Method Type: "+methods[ii].getReturnType());

        }
    }

Загрузка из XML с отражением

public static Object loadFromXml(String filePath) throws Exception {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        File newFile = new File(filePath);
        Document doc = builder.parse(newFile);
        Node root = doc.getFirstChild();

        return loadObjectElement(root);


    }
    /**
     * This method loads from an xml file and returns all the contents of the file as an object
     * @param root The node passed in to the method from which the "tree" gets a new level
     * @return all the contents of the xml file as an object
     * @throws Exception
     */
    public static Object loadObjectElement(Node root) throws Exception {
        //loads the root
        String studentClass = root.getAttributes().getNamedItem("class").getTextContent();
        Object newStudentObject = Class.forName(studentClass).newInstance();
        //gets the children nodes (may have text elements like \n)
        NodeList studentFieldList = root.getChildNodes();

        //iterates through the children nodes
        for (int i = 0; i < studentFieldList.getLength(); i++) {
            //checks to make sure the child node is not a text node
            if (studentFieldList.item(i).getNodeType() != Node.TEXT_NODE) {
                //checks if the current node does not have children
                if (studentFieldList.item(i).getChildNodes().getLength() == 0) {
                    //receives data of the current node
                    String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
                    String valueField = studentFieldList.item(i).getAttributes().getNamedItem("value").getTextContent();
                    Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);

                    //makes the field accessible
                    declaredFieldInClass.setAccessible(true);
                    //checks the field type
                    switch (declaredFieldInClass.getType().getSimpleName().toLowerCase()) {
                        case "integer":
                        case "int":
                            declaredFieldInClass.set(newStudentObject, Integer.valueOf(valueField));
                            break;
                        case "float":
                            declaredFieldInClass.set(newStudentObject, Float.valueOf(valueField));
                            break;
                        case "boolean":
                            declaredFieldInClass.set(newStudentObject, Boolean.valueOf(valueField));
                            break;
                        default:
                            declaredFieldInClass.set(newStudentObject, valueField);
                    }
                    declaredFieldInClass.setAccessible(false);
                } else {
                    //there are children in the current node
                    NodeList modulesObjectList = studentFieldList.item(i).getChildNodes();
                    String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
                    Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
                    List<Object> modules = new ArrayList<>();
                    //adds the modules into the array
                    for (int j = 0; j < modulesObjectList.getLength(); j++) {
                        if (modulesObjectList.item(j).getNodeType() != Node.TEXT_NODE) {
                            //recursively calls the the loadObjectElement method for any sub lists
                            modules.add(loadObjectElement(modulesObjectList.item(j)));
                        }
                    }
                    //sets the modules of the specific student that the method is working with
                    declaredFieldInClass.set(newStudentObject, modules);
                }
            }
        }
        return newStudentObject;
    }
0 голосов
/ 11 апреля 2017

Меня попросили создать решение для следующего утверждения.

"1) Сервис diff, который: • может вычислять различия между двумя объектами и возвращать полученное значение« diff »• может применять ранее созданный« diff »к исходному объекту, чтобы возвращаемый объект соответствовализмененный объект, который использовался для вычисления различий. "

Это было бы очень сложно без использования отражения.Используя отражение, я мог бы перечислить все элементы, свойства и методы класса неизвестного объекта.Я мог бы использовать их, чтобы получить значения, содержащиеся в объекте.Я мог бы сравнить исходные и измененные значения объектов, создать объект «diff», отражающий изменения между двумя объектами.

Используя отражение Java, я мог затем прочитать инструкции в объекте «diff» и применить их к исходному объекту.Отражение Java дало мне инструменты, необходимые для изменения значений неизвестных свойств исходного объекта.Я мог бы вызывать методы установки и создавать экземпляры типов, где это необходимо, если исходное свойство было нулевым, чтобы установить измененное значение для исходного объекта.

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

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

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

0 голосов
/ 30 декабря 2016

Отражение также полезно в тех случаях, когда требуется конфигурация для объединения вещей.Например, в приложении, которое я написал, у меня есть аннотация @Report ("debits"), которая просто добавляется в методы, генерирующие отчеты.Затем в конфигурации XML пользователь может просто добавить:

<requiredReports="debits,blah,another"/>

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

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