static和transient变量序列化问题

看下面的代码:
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方法,那么将会反序列化出不同的对象出来。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值