为什么瞬态变量的状态存储在单例对象中?

时间:2013-02-20 17:13:11

标签: java static singleton transient

package p1;

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


public class SerializationCheck {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        SingletonCompanyCEO s1 = SingletonCompanyCEO.getSingleObject();
        SingletonCompanyCEO s2 = SingletonCompanyCEO.getSingleObject();
        System.out.println("s1==s2:"+(s1==s2));

        ObjectOutputStream obs = new ObjectOutputStream(new FileOutputStream("file.txt"));
        obs.writeObject(s1);

        //first read from file
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file.txt"));
        SingletonCompanyCEO ceo = (SingletonCompanyCEO)ois.readObject();

        //second read from file 
        ois = new ObjectInputStream(new FileInputStream("file.txt"));
        SingletonCompanyCEO ceo1 = (SingletonCompanyCEO)ois.readObject();

        System.out.println("ceo==ceo1:"+(ceo==ceo1)+" (read from file ie. de-serialized )");
        System.out.println(ceo1);


    }
}

class SingletonCompanyCEO implements Serializable
{
    public void setName(String name){
        this.name = name;
    }
    public Object readResolve() throws ObjectStreamException {
        return singleObject;
    }
    private static final long serialVersionUID = 1L;
    private transient int age = 55; // age should set to zero by default as age is transient. But it is not happening, any reason?
    private String name ="Amit";
    float salary = 0f;

    private static SingletonCompanyCEO singleObject;
    private SingletonCompanyCEO()
    {
        if(singleObject!=null)
        {
            throw new IllegalStateException();
        }
    }
    public static SingletonCompanyCEO getSingleObject()
    {
        if(singleObject==null)
        {
            singleObject = new SingletonCompanyCEO();
        }
        return singleObject;
    }
    public String toString()
    {
        return name+" is CEO of the company and his age is "+
        age+"(here 'age' is transient variable and did not set to zero while serialization)";
    }
}

在eclipse编辑器中复制并粘贴此代码。 在序列化时,默认情况下'age'transient变量未设置为零的原因是什么? 序列化表示序列化时瞬态和静态变量设置为零(或默认值)。
在反序列化后,我得到的是age = 55而不是age = 0
在JLS中必须有这样的理由。它是什么?

3 个答案:

答案 0 :(得分:1)

您正在使用SingletonCompanyCEO方法提供静态getSingleObject对象。因此,您SingletonCompanyCEO的以下参考变量,即s1s2共享相同的SingletonCompanyCEO对象。对于此唯一对象,您具有以下字段值:

age = 55; 
name ="Amit";
salary = 0f;

但是您还在readResolve类中覆盖了SingletonCompanyCEO方法,其中您返回s1s2引用的同一对象。因此,在对类JVM进行反序列化时,变量ceoceo1将引用s1s2引用的同一对象。所以基本上你在序列化之前和反序列化之后都有一个SingletonCompanyCEO类的对象。这就是age打印为55的原因。

<强>更新
以下是在代码中删除readResolve后代码中涉及的步骤:

  1. JVM从“file.txt”读取对象 读取对象后,JVM在类readResolve中查找SingletonCompanyCEO方法。 JVM找不到readResolve并将新对象返回到反序列化返回的ceo
  2. JVM再次从“file.txt”中读取对象。 读取对象后,JVM在类readResolve中查找SingletonCompanyCEO方法。 JVM找不到readResolve并将新对象返回到反序列化返回的ceo1
  3.   

    因此,在两次反序列化后,你有两个新的对象   SingletonCompanyCEO
      =&GT; ceo == ceo1返回false   注意:在新创建的对象中,age的值将为JLS指定的0。

    <强> UPDATE2
    如果您对writeobject部分代码发表评论并使用现有文件(file.txt)反序列化该类,则在反序列化时会执行以下步骤:

    1. JVM使用ObjectInputStream从文件中读取对象。 读取对象后,JVM在readResolve()类中查找SingletonCompanyCEO方法。 JVM仅将该对象返回给由类中定义的readResolve()方法返回的变量。
    2. JVM找到readResolve()方法。在readResolve()方法中,您暂时返回singleObject null,因为方法getSingleObject()仍未调用。并且为了您的信息,在反序列化时也不会调用类的构造函数,否则它会像在构造函数中那样抛出IllegalstateException
    3. 由于readResolve()正在返回null因此JVM也返回null。结果ceo1ceo2都是null

答案 1 :(得分:1)

每次反序列化SingletonCompanyCEO对象时,都会丢弃从ObjectInputStream获取的所有信息,而是由于readResolve方法而返回单个对象。 singleObject本身就是一个使用构造函数创建的实例,而不是反序列化,因此它的年龄为55岁。

答案 2 :(得分:0)

private transient int age = 55;

在声明中定义值时,这将优先。