Объекты в памяти. Обход поля и значения в Java - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть сценарий, в котором мне нужно пройти по сложному объекту в памяти. Мне нужно пройти по ключу и значению всего дерева и к нужному материалу. Есть ли способ сделать это? Его нельзя сериализовать до JSON, что является большой проблемой. Таким образом, единственный способ состоит в том, чтобы пройти объект, когда он загружен в память.

enter image description here

Объект на самом деле выглядит следующим образом. Он может иметь глубокое вложение и GSON или любая другая библиотека не может сериализовать ее в JSON.

1 Ответ

0 голосов
/ 07 апреля 2020

Очень, очень сложно.

Для любого объекта получите все его поля:

Class<?> c = obj.getClass();
var fields = new ArrayList<Field>();
while (c != null) {
   for (Field f : c.getDeclaredFields()) {
       if (Modifier.isStatic(f.getModifiers())) continue;
       f.setAccessible(true);
       fields.add(f);
    }
    c = c.getSuperclass();
}

Похоже, много работы, но вы должны использовать вариант declaredFields для также получите доступ к закрытым полям, и он не будет автоматически обходить иерархию супертипов для вас. Получив этот список, вы можете просто установить объект для этого поля, используя обычный field.get(obj). Затем ... примените тот же алгоритм рекурсивно к ЭТИМ объектам для построения такой иерархии.

Проблема: Массивы

массивы требуют особого внимания. Вы не можете просто спросить это для его полей; его не будет. Следовательно, вам нужно это, после использования field.get(obj):

if (a.getClass().isArray()) {
    int len = Array.getLength(a);
    for (int i = 0; i < len; i++) {
        Object actualContent = Array.get(a, i);
    }
}

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

Проблема: Это тонна материала для печати!

Да, это так - одна строка имеет char[] внутри. Возможно, вы захотите выполнить несколько экземпляров проверок и пользовательских принтеров с «жестким кодом» для известных типов, таких как String.

Проблема: JDK11 + о чем-то предупреждает.

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

Проблема: Циклы / самоссылка

Возможно, что объекты ссылаются на себя в al oop. Например:

List<Object> list = new ArrayList<Object>();
list.add(list);

// or a cycle:

List<Object> list1 = new ArrayList<Object>();
List<Object> list2 = new ArrayList<Object>();
list1.add(list2);
list2.add(list1);

, что приведет к тому, что ваш код печати будет l oop навсегда. Решение этой проблемы состоит в том, чтобы отслеживать идентичность объекта, и если вы найдете объект, который вы уже «видели», не печатайте его вообще, просто напечатайте некоторую ссылку. Это также требует, чтобы вы распечатали ссылку на каждый объект. Чтобы получить число, идентифицирующее объект, используйте System.identityHashCode, который гарантированно сделает действительно хорошую попытку дать вам уникальный идентификатор (но не гарантируется 100%, что каждый объект обязательно получит уникальный идентификатор). Чтобы проверить, видели ли вы уже объект, используйте IdentityHashMap, где значение карты не имеет значения (если бы было IdentityHashSet, я бы сказал вам использовать это, но это не так. Просто карта вместо "" и проверьте наличие ключа).

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

Или просто положитесь на свою IDE для сделайте это, возможно, есть лучшие решения для любой проблемы, которая заставила вас go: я знаю! Я распечатаю все сырое содержимое этого объекта, рекурсивно! - но твой вопрос не включает, почему ты этого хочешь.

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