Является ли десериализованный объект тем же экземпляром, что и оригинал

Когда я создаю экземпляр объекта из класса, объект сохраняется в куче java. Когда я сохраняю объект, сериализуя его, а позже десериализую объект, правильно ли понимаю, что у объекта теперь будет новый адрес кучи, но все равно будет ТОЧНЫМ экземпляром класса.

Ответы

Ответ 1

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

  • Все java-объекты создаются в java-куче (кроме некоторых, которые хранится в пуле, но для вас вопрос, мы пропустим их пока).
  • Когда экземпляр класса создается с использованием нового ключевого слова, десериализация, метод клона или отражение api newInstance метод, новое пространство в куче зарезервировано, и мы присваиваем его ссылке на объект (ссылка может быть класса объекта или одного из супер классы класса объектов - снова мы можем игнорировать эту деталь для в настоящее время).
  • Когда вы сохраняете свой объект, состояние объекта сохраняется со всеми его вложенных объектов.
  • При десериализации объекта объект создаст новую запись в куче, которая не будет иметь никаких ссылок на какие-либо объекты.

Посмотрите на приведенную ниже диаграмму для иллюстрации вышеуказанной концепции в вашем контексте:

enter image description here

Все ссылки на объект A указывают на одну запись кучи, и если вы попытаетесь objectB.getObjectA() == objectC.getObjectA() или любую другую такую ​​операцию, вы получите правду.

Случай 1 Когда вы сохраняете объекты отдельно и десериализуете их, вот что происходит в куче:

enter image description here

Как вы теперь можете понять, что objectBcopy.getObjectA() == objectCcopy.getObjectA() не вернет true, поскольку ссылки на объект A для скопированных объектов уже не такие.

Случай 2. Наоборот, когда вы сохраняете объекты в одном файле и десериализуете их позже, вот что происходит в куче:

enter image description here

Как вы теперь можете понять, что objectBcopy.getObjectA() == objectCcopy.getObjectA() теперь будет истинным, так как ссылки объекта копируются одинаково, но это еще новая копия объекта А.

Быстрая программа для поддержки моих вычетов (случай 1 и случай 2):

public class Test{

    public static void main (String args[]) throws IOException, ClassNotFoundException{
        A a = new A();

        B b = new B();
        b.a = a;

        C c = new C();
        c.a = a;

        System.out.println("b.a == c.a is " + (b.a == c.a));

        // Case 1 - when two diferent files are used to write the objects
        FileOutputStream fout = new FileOutputStream("c:\\b.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(b);
        oos.close();
        fout.close();

        fout = new FileOutputStream("c:\\c.ser");
        oos = new ObjectOutputStream(fout);
        oos.writeObject(c);
        oos.close();
        fout.close();

        FileInputStream fileIn = new FileInputStream("c:\\b.ser");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        B bCopy = (B) in.readObject();
        in.close();
        fileIn.close();

        fileIn = new FileInputStream("c:\\c.ser");
        in = new ObjectInputStream(fileIn);
        C cCopy = (C) in.readObject();
        in.close();
        fileIn.close();
        System.out.println("Case 1 - bCopy.a == cCopy.a is " + (bCopy.a == cCopy.a));

        // Case 2 - when both the objects are saved in the same file
        fout = new FileOutputStream("c:\\both.ser");
        oos = new ObjectOutputStream(fout);
        oos.writeObject(b);
        oos.writeObject(c);
        oos.close();
        fout.close();


        fileIn = new FileInputStream("c:\\both.ser");
        in = new ObjectInputStream(fileIn);
        bCopy = (B) in.readObject();
        cCopy = (C) in.readObject();
        in.close();
        fileIn.close();
        System.out.println("Case 2 - bCopy.a == cCopy.a is " + (bCopy.a == cCopy.a));
    }
}

class A implements Serializable{

}

class B implements Serializable{
    A a;
}

class C implements Serializable{
    A a;
}

Со следующим выходом:

 b.a == c.a is true
 Case 1 - bCopy.a == cCopy.a is false
 Case 2 - bCopy.a == cCopy.a is true

Ответ 2

Перед сериализацией:

A originalA = ...;
B.a == C.a == D.a == E.a == originalA

Все B.a, C.a, D.a и E.a указывают на ту же ссылку A, originalA.

После сериализации и десериализации:

A otherA = ...;
B.a == C.a == D.a == E.a == otherA

Все B.a, C.a, D.a и E.a указывают на ту же ссылку A, otherA.

Однако:

originalA != otherA

хотя

originalA.equals(otherA) == true

Примечание: equals() вернет true, только если он переопределит, чтобы последовательно проверять равенство на основе сериализованных полей. В противном случае он может вернуться false.


EDIT:

Доказательство:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Sample {

    static class A implements Serializable {
        private static final long serialVersionUID = 1L;
    }

    static class B implements Serializable {
        private static final long serialVersionUID = 1L;

        A a;
    }

    static class C implements Serializable {
        private static final long serialVersionUID = 1L;

        A a;
    }

    public static void main(String args[]) throws IOException, ClassNotFoundException {
        A originalA = new A();

        B b = new B();
        b.a = originalA;

        C c = new C();
        c.a = originalA;

        System.out.println("b.a == c.a is " + (b.a == c.a));

        FileOutputStream fout = new FileOutputStream("ser");
        ObjectOutputStream oos = new ObjectOutputStream(fout);
        oos.writeObject(b);
        oos.writeObject(c);
        oos.close();
        fout.close();

        FileInputStream fileIn = new FileInputStream("ser");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        B bDeserialized = (B) in.readObject();
        C cDeserialized = (C) in.readObject();
        in.close();
        fileIn.close();

        System.out.println("bDeserialized.a == cDeserialized.a is " + (bDeserialized.a == cDeserialized.a));
    }
}

Ответ 3

Нет. Простой ответ заключается в том, что десериализованный объект не будет тем же самым экземпляром в памяти! Он будет выделять новую память для этого же. Также перейдите по ссылке http://www.javalobby.org/java/forums/t17491.html, которая содержит пример извлечения объекта с помощью десериализации с помощью singleton! Также перейдите через readResolve ( ) в глубину, в некоторых случаях это будет полезно.

Ответ 4

десериализованный экземпляр определенно будет отличным экземпляром от оригинала, так как в deserialized != original всегда будет true.

Депериализованный экземпляр может быть или не быть равным исходному экземпляру, как в deserialized.equals(original). Для разумной реализации класса Serializable equals, вероятно, будет истинным после десериализации, но тривиально создать класс, для которого это не выполняется:

class Pathological implements Serializable {
  transient int value;

  Pathological(int value) { this.value = value; }

  @Override public int hashCode() { return value; }

  @Override public boolean equals(Object other) {
    if (other == this) { return true; }
    if (other instanceof Pathological) {
      return ((Pathological) other).value == this.value;
    }
    return false;
  }
}

Если при построении Pathological вам не удастся пройти нуль, экземпляры не будут равны после сериализации/десериализации, так как значение value не будет сериализовано (поскольку оно является временным).

Ответ 5

Нет, они не будут тем же самым объектом в памяти originalObj == deserilized будет ложным, однако originalObj.equals(deserilized) должен быть правдой.

Объекты B, C, D и E. Все из них при создании экземпляра имели объект A. Тогда допустим, что я сериализую и десериализую их все. Когда я изменяю поле Object A после десериализации, есть ли способ отразить такое изменение в объекте A (s) в BCDE?

Если вы правильно поняли, что ответ отрицательный, ссылки не будут указывать на один и тот же объект A

Однако, если вы так желаете, вы можете явно указать все ссылки объекта A в каждом объекте B, C, D и E, чтобы указать на тот же экземпляр объекта A

Вот демоверсия, чтобы проиллюстрировать сделанные баллы.

import java.io.*;
import java.util.*;

public class Demo {  
  public static void main(String... aArguments) {  
    List<Quark> quarks = Arrays.asList(
      new Quark("up"), new Quark("down")
    );

    serialize(quarks);
    List<Quark> recoveredQuarks = deserialize();

    System.out.println(quarks == recoveredQuarks);               // false
    System.out.println(quarks.equals(recoveredQuarks));          // true

    System.out.println(quarks.get(0) == recoveredQuarks.get(0)); // false

    // but you can set it to the same instance
    recoveredQuarks.set(0, quarks.get(0));
    System.out.println(quarks.get(0) == recoveredQuarks.get(0)); // true

    quarks.get(0).name = "Charm";
    boolean b = quarks.get(0).name == recoveredQuarks.get(0).name;
    System.out.println(b);                                       // true
  }

  static void serialize(List<Quark> quarks) {
    try {
      OutputStream file = new FileOutputStream("quarks.ser");
      OutputStream buffer = new BufferedOutputStream(file);
      ObjectOutput output = new ObjectOutputStream(buffer);
      output.writeObject(quarks);
      output.close();
    }
    catch(IOException ex) { ex.printStackTrace(); }
  }

  static List<Quark> deserialize() {
    List<Quark> recoveredQuarks = null;
    try {
      InputStream file = new FileInputStream("quarks.ser");
      InputStream buffer = new BufferedInputStream(file);
      ObjectInput input = new ObjectInputStream(buffer);
      recoveredQuarks = (List<Quark>)input.readObject();
      input.close();
    } 
    catch(ClassNotFoundException ex){ }
    catch(IOException ex){ ex.printStackTrace(); }
    return recoveredQuarks;
  }
}

class Quark implements Serializable {
    String name;
    Quark(String name) {
      this.name = name;
    }

    @Override
    public boolean equals(Object o) {
      if (o != null && o instanceof Quark) {
        return this.name.equals(((Quark)o).name);
      }
      return false;
    }
}