看下面的代码:
1.Person.java
2.DataObject.java
3.运行以后发现上面的输出结果,我们说static变量不能被序列化,但是现在为什么我们看到的object和object2的状态却是连续的呢?
4.我们在最后添加上一些代码来继续这个问题:
看到什么了?
第一句:序列化以前的和序列化以后的不是同一个对象!这不是废话嘛,我们都知道!
第二句:竟然输出了true!
第三句:输出false,本来就应该是false才对嘛。看出点什么?难道object.p和object2.p本来就是同一个对象实例?可不是嘛!同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,object.p并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!
其实第二句完全等价于:System.out.println(DataObject.p==DataObject.p);//true,这样就更好理解了!并且就算Person类没有实现Serializable接口,如果是静态的,照样能读出来,但是却不是序列化的原因!
5. 你也许要问了,如果JVM中没有这个静态实例会是怎么样的呢?下面我们就来看一看:
/*
打印输出:
构建一个Person对象
hello:world
*/
这回我们看得很清楚了,因为这个新启动的JVM内部并没有事先已经存在一个Person对象实例,所以当反序列化的时候,由于反序列化构建一个对象属于对类的主动使用,所以会对类进行初始化,对类的静态变量进行赋值,所以我们看到的是只是经过初始化以后的对象实例,而不是序列化以前的那个实例,因此也就无法保持状态的连续了!6.那么对于transient变量又是怎么样的呢?
我们修改代码:
运行以后发现输出:
/*
构建一个Person对象
序列化以前:why
Exception in thread "main" java.lang.NullPointerException
at Data2Object.toString(Data2Object.java:8)
at java.lang.String.valueOf(String.java:2827)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at Data2Object.main(Data2Object.java:22)
*/
也就是说反序列化以后根本就找不到transient变量,因为transient根本就没有被序列化! 看一个序列化的例子:
country本身实现了Serializable接口,可以进行序列化,而其中的成员除了name都是static。为了在反序列化的时候得到Country里面的静态成员,就需要提供一个readResolve()方法,用它来返回Map里面的静态实例。
如果注释掉readResolve方法,那么将会反序列化出不同的对象出来。
1.Person.java
import java.io.*;
class Person implements Serializable{ public String name;
public Person(String name){
this.name=name;
System.out.println("构建一个Person对象");
}
}
2.DataObject.java
import java.io.*;
public class DataObject implements Serializable
{
public static Person p=new Person("hello");//静态的
public Person p2=new Person("world");//非静态的
public String toString() {
return p.name+":"+p2.name;
}
public static void main(String[] args) throws ClassNotFoundException,FileNotFoundException,IOException
{
DataObject object=new DataObject();
object.p.name="why";
System.out.println("序列化以前:"+object); //序列化以前:why:world
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("lql.out"));
out.writeObject(object);
ObjectInputStream in=new ObjectInputStream(new FileInputStream("lql.out"));
DataObject object2=(DataObject)in.readObject();
System.out.println("序列化以后:"+object2); //序列化以后:why:world }
}
3.运行以后发现上面的输出结果,我们说static变量不能被序列化,但是现在为什么我们看到的object和object2的状态却是连续的呢?
4.我们在最后添加上一些代码来继续这个问题:
System.out.println("object==object2?"+(object==object2)); //false
System.out.println("object.p==object2.p?"+(object.p==object2.p));//true
System.out.println("object.p2==object2.p2?"+(object.p2==object2.p2));//false
看到什么了?
第一句:序列化以前的和序列化以后的不是同一个对象!这不是废话嘛,我们都知道!
第二句:竟然输出了true!
第三句:输出false,本来就应该是false才对嘛。看出点什么?难道object.p和object2.p本来就是同一个对象实例?可不是嘛!同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,object.p并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!
其实第二句完全等价于:System.out.println(DataObject.p==DataObject.p);//true,这样就更好理解了!并且就算Person类没有实现Serializable接口,如果是静态的,照样能读出来,但是却不是序列化的原因!
5. 你也许要问了,如果JVM中没有这个静态实例会是怎么样的呢?下面我们就来看一看:
import java.io.*;
public class SerTest{
public static void main(String[] args) throws ClassNotFoundException,FileNotFoundException,IOException
{
ObjectInputStream in=new ObjectInputStream(new FileInputStream("lql.out"));
DataObject object2=(DataObject)in.readObject();
System.out.println(object2);
}
}
/*
打印输出:
构建一个Person对象
hello:world
*/
这回我们看得很清楚了,因为这个新启动的JVM内部并没有事先已经存在一个Person对象实例,所以当反序列化的时候,由于反序列化构建一个对象属于对类的主动使用,所以会对类进行初始化,对类的静态变量进行赋值,所以我们看到的是只是经过初始化以后的对象实例,而不是序列化以前的那个实例,因此也就无法保持状态的连续了!6.那么对于transient变量又是怎么样的呢?
我们修改代码:
import java.io.*;
public class Data2Object implements Serializable
{
public transient Person p=new Person("hello")
public String toString() {
return p.name;
}
public static void main(String[] args) throws ClassNotFoundException,FileNotFoundException,IOException
{
Data2Object object=new Data2Object();
object.p.name="why";
System.out.println("序列化以前:"+object);
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("lql.out"));
out.writeObject(object);
ObjectInputStream in=new ObjectInputStream(new FileInputStream("lql.out"));
Data2Object object2=(Data2Object)in.readObject();
System.out.println("序列化以后:"+object2);
System.out.println("object==object2?"+(object==object2));
System.out.println("object.p==object2.p?"+(object.p==object2.p));
}
}
运行以后发现输出:
/*
构建一个Person对象
序列化以前:why
Exception in thread "main" java.lang.NullPointerException
at Data2Object.toString(Data2Object.java:8)
at java.lang.String.valueOf(String.java:2827)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at Data2Object.main(Data2Object.java:22)
*/
也就是说反序列化以后根本就找不到transient变量,因为transient根本就没有被序列化! 看一个序列化的例子:
import java.util.*;
import java.io.*;public final class Country implements Serializable{
private static final Map INDEX=new HashMap();
public static final Country CANADA =new Country("CANADA");
public static final Country US=new Country("US");
public static final Country EN =new Country("EN");
public static final Country CHINA =new Country("CHINA");
private String name;
private Country(String name){
this.name=name;
INDEX.put(name,this);
}
private static Country lookup(String name){
return (Country)INDEX.get(name);
}
public String toString(){
return this.name;
}
private Object readResolve()throws ObjectStreamException{
Country c=lookup(name);
return c;
}
public static void main(String rags[]){
System.out.println(Country.lookup("CHINA"));
}
}
country本身实现了Serializable接口,可以进行序列化,而其中的成员除了name都是static。为了在反序列化的时候得到Country里面的静态成员,就需要提供一个readResolve()方法,用它来返回Map里面的静态实例。
import java.util.*;
import java.io.*;public final class SerTest{
public static void main(String rags[])throws Exception{
FileOutputStream fout=new FileOutputStream("test.out");
ObjectOutputStream oout=new ObjectOutputStream(fout);
oout.writeObject(Country.CHINA);
System.out.println(Country.CHINA.hashCode());
fout.close();
oout.close();
FileInputStream fin=new FileInputStream("test.out");
ObjectInputStream oin=new ObjectInputStream(fin);
Country c=(Country)oin.readObject();
System.out.println(c.hashCode());
fin.close();
oin.close();
System.out.println(c==Country.CHINA);
}
}
如果注释掉readResolve方法,那么将会反序列化出不同的对象出来。