Автоматическое переключение указателей с помощью Java?

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

class Node
{
    public ValueType data;
    public ArrayList<Node> adj;
}

Теперь я хочу сделать его копию или записать/прочитать его на диск (также известный как сериализация/десериализация). Я также знаю, что это можно сделать с помощью алгоритма поиска + ассоциативные массивы. И, оказывается, этот метод называется swizzling.

А вот и мой вопрос:

Я слышал, что в Java, объявляя класс Serializable, эта функция предоставляется вам автоматически. (что для меня звучит как магия!)

Это утверждение верно? Запускает ли Java автоматически BFS для обхода графа и перемещения указателей? Другими словами, выполняет ли сериализация/десериализация клонирование объекта для меня? (совершенно новый объект с той же структурой, но с новыми узлами и обновленными указателями)

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

Я ценю любые комментарии по этому поводу. :-)


person Nima    schedule 29.02.2012    source источник
comment
В Java нет необработанных указателей; у вас нет доступа к реальному адресу памяти. У вас есть ссылки на объекты (которые на самом деле являются указателями, но не пытайтесь никому об этом говорить, и не путайте их со ссылками C++, потому что они таковыми не являются).   -  person Brian Roach    schedule 29.02.2012
comment
Прочтите об этом. Это все в документации, если вы посмотрите.   -  person Hot Licks    schedule 29.02.2012
comment
@BrianRoach: извините за ошибку. Я был в мышлении C++.   -  person Nima    schedule 29.02.2012


Ответы (2)


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

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

person mmx    schedule 29.02.2012
comment
С++ ходил, задаваясь вопросом, как?! :O, и Ява подмигнул. чудесный! Я имею в виду язык, который недавно добавил переключатель регистра для строк. - person Nima; 29.02.2012

Я не думаю, что это совсем то, что вы думаете об этом, но в значительной степени. Сериализация в Java — довольно непрозрачный процесс. Все, что вам действительно нужно знать об этом, это то, что при условии, что класс и все типы его членов реализуют Serializable, Java знает, как преобразовать его в поток байтов и как воссоздать экземпляры объектов из этого потока, когда вы просите его десериализовать.

Пришедшее из C++, поначалу это казалось черной магией. Я скептически относился ко всему процессу и не очень доверял JVM, чтобы он позаботился об этом за меня, потому что в C++ он просто недостаточно знает о простом объекте, чтобы сделать это. Но на самом деле это очень удобно, если вам нужно получить доступ к данным только из Java.

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

И еще: если вы объявите переменную как transient, она не будет сохранена и вам придется восстанавливать ее самостоятельно. Это полезно, если у вас есть поля, которые кэшируют определенные значения, для которых вы не хотите тратить место, или поля с конфиденциальными данными, которые вы не хотите хранить. Но вам придется не забыть восстановить его самостоятельно.

person parkovski    schedule 29.02.2012