Java 反序列化对象是否与原始对象具有相同的实例

Java 反序列化对象是否与原始对象具有相同的实例,java,serialization,Java,Serialization,当我从一个类实例化一个对象时,一个对象保存在java堆中。当我通过序列化来保存对象,然后反序列化该对象时,我是否正确理解该对象现在将有一个新的堆地址,但仍然是该类的完全相同的实例。否,简单的答案是反序列化的对象在内存中不会是相同的实例!它将为相同的对象分配新的内存。也要浏览包含使用singleton反序列化检索对象示例的链接!此外,还要深入了解readResolve()方法,它在某些情况下会有所帮助。反序列化的实例肯定会是与原始实例不同的实例,如反序列化!=原始的将始终为真 反序列化的实例可能等

当我从一个类实例化一个对象时,一个对象保存在java堆中。当我通过序列化来保存对象,然后反序列化该对象时,我是否正确理解该对象现在将有一个新的堆地址,但仍然是该类的完全相同的实例。

否,简单的答案是反序列化的对象在内存中不会是相同的实例!它将为相同的对象分配新的内存。也要浏览包含使用singleton反序列化检索对象示例的链接!此外,还要深入了解readResolve()方法,它在某些情况下会有所帮助。

反序列化的实例肯定会是与原始实例不同的实例,如
反序列化!=原始的
将始终为真

反序列化的实例可能等于或不等于原始实例,如反序列化的.equals(original)中所述。对于
可序列化
类的合理实现,
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;
  }
}

除非在构造
value
时恰好通过零,否则序列化/反序列化后实例将不相等,因为
value
的值不会被序列化(因为它是瞬态的)。

否它们在内存中不会是相同的对象
originalObj==反序列化的
将为false,但是,
originalObj.equals(反序列化)
应该为true

对象B、C、D和E。所有这些对象在实例化时都有对象A。然后,假设我序列化和反序列化了它们。当我在反序列化后更改对象a的字段时,是否有办法在BCDE中的对象a中反映这种更改


如果我理解正确,答案是否定的,引用将不会指向同一个对象A

但是,如果需要,可以显式地将每个对象B、C、D和E中对象A的所有引用设置为指向对象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;
    }
}
import java.io.*;
导入java.util.*;
公共类演示{
公共静态void main(字符串…aArguments){
List quarks=Arrays.asList(
新夸克(“上”),新夸克(“下”)
);
序列化(夸克);
List recoveredQuarks=反序列化();
System.out.println(quarks==recoveredQuarks);//false
System.out.println(quarks.equals(recoveredQuarks));//true
System.out.println(quarks.get(0)=recoveredQuarks.get(0));//false
//但您可以将其设置为相同的实例
恢复的夸克集(0,夸克集(0));
System.out.println(quarks.get(0)=recoveredQuarks.get(0));//true
quarks.get(0).name=“Charm”;
布尔b=quarks.get(0).name==recoveredQuarks.get(0).name;
System.out.println(b);//true
}
静态空序列化(列出夸克){
试一试{
OutputStream文件=新文件OutputStream(“quarks.ser”);
OutputStream buffer=新的BufferedOutputStream(文件);
ObjectOutput=新的ObjectOutputStream(缓冲区);
output.writeObject(夸克);
output.close();
}
catch(IOException ex){ex.printStackTrace();}
}
静态列表反序列化(){
List recoveredQuarks=null;
试一试{
InputStream文件=新文件InputStream(“quarks.ser”);
InputStream buffer=新的BufferedInputStream(文件);
ObjectInput输入=新ObjectInputStream(缓冲区);
recoveredQuarks=(列表)input.readObject();
input.close();
} 
catch(ClassNotFoundException ex){}
catch(IOException ex){ex.printStackTrace();}
返回恢复夸克;
}
}
类Quark实现可序列化{
字符串名;
Quark(字符串名称){
this.name=名称;
}
@凌驾
公共布尔等于(对象o){
if(o!=null&&o夸克实例){
返回此.name.equals(((Quark)o).name);
}
返回false;
}
}
序列化之前:

A originalA = ...;
B.a == C.a == D.a == E.a == originalA
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
所有
B.a
C.a
D.a
E.a
都指向
a
原代码的相同参考

序列化和反序列化后:

A originalA = ...;
B.a == C.a == D.a == E.a == originalA
A otherA = ...;
B.a == C.a == D.a == E.a == otherA
所有
B.a
C.a
D.a
E.a
都指向
a
其他a
的同一参考

然而:

originalA != otherA
虽然

originalA.equals(otherA) == true
注意:
equals()
仅当它被覆盖时才会返回
true
,以基于序列化字段一致地检查相等性。否则,它可能返回
false


编辑:

证明:

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));
    }
}

对你的问题的回答不能是“是”或“否”。需要分析概念。我建议你拿一支铅笔和一张纸,自己动手,记住以下几点

  • 所有java对象都是在java堆中创建的(除了一些 保留在游泳池中,但对于您的问题,我们现在将跳过它们)
  • 使用new关键字创建类的实例时, 反序列化、克隆方法或反射api的newInstance方法, 在堆中保留一个新空间,并将其分配给对象引用 (引用可以是对象的类,也可以是超级 对象类的类-同样,我们可以忽略这个细节 现在)
  • 保存对象时,对象的状态将与其所有属性一起保存 嵌套对象
  • 当您反序列化对象时,该对象将创建一个新条目 在堆中,它将不具有对任何对象的任何引用
查看下图,在您的上下文中描绘上述概念:

所有对象A引用都指向一个堆条目,如果您尝试objectB.getObjectA()==objectC.getObjectA()或任何其他类似操作,您将得到true

保存对象时,情况1