Подтвердить что ты не робот

Сохраняет ли сериализация идентификатор объекта?

Я использую интерфейс Java Serializable и ObjectOutputStream для сериализации объектов (до сих пор этого метода было достаточно для моих целей).

Мой API полагается на идентификатор объекта для некоторых операций, и мне интересно, сохранится ли он путем сериализации. То есть: , если для двух произвольных объектов a и b он сохраняет a == b перед сериализацией, сохраняется ли она после десериализации?

Ive нашел несколько текстов, которые утверждают об обратном - но они либо писали о более старой версии JRE (Im интересовался только 1.6 и, возможно, 1.5), или были связаны с RMI (что не имеет для меня значения).

Документация не очень подходит для идентификации объекта. Техническая статья на sun.com упоминает, что ObjectOutputStream использует кеширование объектов, что для меня имеет смысл только в том случае, если идентичность объекта действительно сохранена, но Я не достаточно уверен, чтобы полагаться на это необоснованное доказательство.

Ive попробовал это (Java 1.6, OS X) и обнаружил, что да, идентификация объектов остается неизменной путем сериализации. Но могу ли я экстраполировать эти результаты или они ненадежны?

Для моего теста Ive сериализовал следующий граф объектов:

C----------+
| b1    b2 |
+----------+
  |      |
  v      v
B---+  B---+
| a |  | a |
+---+  +---+
   \    /
    \  /
     \/
   A----+
   |    |
   +----+

Минимальный код воспроизведения:

import java.io.*;

public class SerializeTest {
    static class A implements Serializable {}

    static class B implements Serializable {
        final A a;

        public B(A a) {
            this.a = a;
        }
    }

    static class C implements Serializable {
        final B b1, b2;

        public C() {
            A object = new A();
            b1 = b2 = new B(object);
        }
    }

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        C before = new C();
        System.out.print("Before: ");
        System.out.println(before.b1.a == before.b2.a);

        // Serialization.
        ByteArrayOutputStream data = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(data);
        out.writeObject(before);
        out.close();

        // Deserialization.
        ObjectInputStream in =
            new ObjectInputStream(new ByteArrayInputStream(data.toByteArray()));
        C after = (C) in.readObject();
        System.out.print("After: ");
        System.out.println(after.b1.a == after.b2.a);
    }
}
4b9b3361

Ответ 1

Для двух произвольных объектов a и b, если он содержит a == b перед сериализацией, он будет сохраняться и после десериализации IF:

  • Оба a и b записываются как и впоследствии считываются из частей одного и того же потока. Здесь приведена цитата из ObjectInputStream:" Графы объектов восстанавливаются корректно с помощью механизма обмена ссылками.
  • Класс a и b не переопределяет readResolve(), который имеет потенциал изменения способа восстановления ссылок; ни классы, которые содержат a и b.

Для всех остальных случаев идентификация объекта НЕ будет сохранена.

Ответ 2

Ответ нет, по умолчанию идентификация объекта не сохраняется через сериализацию, если вы рассматриваете две отдельные сериализации данного объекта/графика. Например, если я сериализую объект по проводке (возможно, я отправлю его от клиента на сервер через RMI), а затем повторю его (в отдельных вызовах RMI), то 2 десериализованных объекта на сервере не будут ==.

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

В первом случае вы можете, однако, обеспечить реализацию метода readResolve, чтобы убедиться, что правильный экземпляр (например, в шаблоне перечисления типов). readResolve - это частный метод, который будет вызываться JVM на де-сериализованном Java-объекте, предоставляя объекту возможность вернуть другой экземпляр. Например, таким образом, как TimeUnit enum может быть реализовано до того, как enum были добавлены в язык:

public class TimeUnit extends Serializable {

    private int id;
    public TimeUnit(int i) { id = i; }
    public static TimeUnit SECONDS = new TimeUnit(0);

    //Implement method and return the relevant static Instance
    private Object readResolve() throws ObjectStreamException {
        if (id == 0) return SECONDS;
        else return this;
    }
}

.