Any time a SingletonCompanyCEO object is deserialized, all information obtained from the ObjectInputStream is discarded and instead your singleObject is returned, due to your readResolve
method. singleObject is itself an instance which was created using the constructor, not deserialization, so its age is 55.
why transient variable's state is stored in singleton object?
Question
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)";
}
}
copy and paste this code in eclipse editor.
What is the reason where 'age' transient
variable is not set to zero by default while serialization?
Serialization says that transient and static variable are set to zero(or default values) while serialization.
After de-serialization I am getting age = 55
instead of age = 0
.
There must be reason behind this in JLS. What is it?
La solution
Autres conseils
You are providing a static SingletonCompanyCEO
object using getSingleObject
method. So your following reference variables of SingletonCompanyCEO
i.e s1
, s2
are sharing the same SingletonCompanyCEO
object. For this unique object you have following value for fields:
age = 55;
name ="Amit";
salary = 0f;
But you have also overridden readResolve
method in SingletonCompanyCEO
class where you are returning the same object to which s1
and s2
are referencing. So while deserializing the class JVM makes the variable ceo
and ceo1
to reference the same object to which s1
and s2
are referencing. So basically you have a single object of SingletonCompanyCEO
class before serialization and after deserialization. That's why the age
is printing as 55
.
UPDATE:
Here are the steps that is involving in your code after readResolve
is removed in your code :
- JVM reads the Object from "file.txt"
After object is read JVM looks for
readResolve
method in classSingletonCompanyCEO
. JVM does not findreadResolve
and returns the new object toceo
as returned by deserialization. - JVM again reads the object from "file.txt".
After object is read JVM looks for
readResolve
method in classSingletonCompanyCEO
. JVM does not findreadResolve
and returns the new object toceo1
as returned by deserialization.
Hence after two deserialization you have two new objects of
SingletonCompanyCEO
.
=> ceo==ceo1 returns false.
NOTE: In both newly created objects value ofage
will be 0 as specified by JLS.
UPDATE2
if you comment writeobject
parts of code and deserialize the class using already existing file (file.txt
) Then following steps takes place while deserialization:
- JVM reads the object from the file using ObjectInputStream.
After the object is read JVM looks for
readResolve()
method inSingletonCompanyCEO
class. JVM returns only that object to the variable which is returned byreadResolve()
method defined in class. - JVM finds the
readResolve()
method. InreadResolve()
method you had returnedsingleObject
which isnull
for now as the methodgetSingleObject()
is still not called up. And for your information, the constructor of class is also not called while deserialization , else it would have thrownIllegalstateException
as you have done in constructor. - Since
readResolve()
is returningnull
Hence JVM is also returningnull
. Consequentyceo1
andceo2
both arenull
.
private transient int age = 55;
When you define a value at declaration, this takes priority.