static和transient变量序列化问题

来源:互联网 发布:mac淘宝卖家 编辑:程序博客网 时间:2024/06/16 20:42
看下面的代码:
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));    //falseSystem.out.println("object.p==object2.p?"+(object.p==object2.p));//trueSystem.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方法,那么将会反序列化出不同的对象出来。
0 0
原创粉丝点击