Java自定义序列化行为解析

正常情况下,一个类实现java序列化很简单,只需要implements Serializable接口即可,之后该类在跨jvm的传输过程中会遵照默认java序列化规则序列化和反序列化;不同jvm版本之间序列化方式稍有不同,但基本上都是兼容的。

在肃北等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站设计、成都做网站、外贸网站建设 网站设计制作按需定制设计,公司网站建设,企业网站建设,成都品牌网站建设,全网整合营销推广,外贸网站制作,肃北网站建设费用合理。

在某些特殊情况下,可能需要自定义序列化和反序列化的行为,看下面例子:

Java代码

 
 
 
  1. class AbstractSerializeDemo {   
  2.     private int x, y;   
  3.   
  4.     public void init(int x, int y) {   
  5.         this.x = x;   
  6.         this.y = y;   
  7.     }   
  8.   
  9.     public int getX() {   
  10.         return x;   
  11.     }   
  12.   
  13.     public int getY() {   
  14.         return y;   
  15.     }   
  16.   
  17.     public void printXY() {   
  18.         System.out.println("x:" + x + ";y:" + y);   
  19.     }   
  20. }   
  21.   
  22. public class SerializeDemo extends AbstractSerializeDemo implements Serializable {   
  23.     private int z;   
  24.   
  25.     public SerializeDemo() {   
  26.         super.init(10, 50);   
  27.         z = 100;   
  28.     }   
  29.   
  30.     public void printZ() {   
  31.         super.printXY();   
  32.         System.out.println("z:" + z);   
  33.     }   
  34.   
  35.     public static void main(String[] args) throws IOException, ClassNotFoundException {   
  36.         ByteArrayOutputStream bos = new ByteArrayOutputStream();   
  37.         ObjectOutputStream out = new ObjectOutputStream(bos);   
  38.         SerializeDemo sd = new SerializeDemo();   
  39.         sd.printZ();   
  40.         out.writeObject(sd);   
  41.         ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));   
  42.         SerializeDemo sd2 = (SerializeDemo) in.readObject();   
  43.         sd2.printZ();   
  44.     }   

这段程序表示了一个可序列化的类继承自一个非序列化的有状态超类,期望的结果是,子类序列化以后传输并反序列化回来,原先的值域包括超类的值域都保持不变。

但是输出是:

Java代码

 
 
 
  1. x:10;y:50  
  2. z:100  
  3. x:0;y:0  
  4. z:100  

结果和期望不符,子类的值域保留下来了,但是超类的值域丢失了,这对jvm来说是正常的,因为超类不可序列化;

为了解决这个问题,只能自定义序列化行为,具体做法是在SerializeDemo里加入以下代码:

Java代码

 
 
 
  1. private void writeObject(ObjectOutputStream os) throws IOException {   
  2.       os.defaultWriteObject();//java对象序列化默认操作   
  3.       os.writeInt(getX());   
  4.       os.writeInt(getY());   
  5.   }   
  6.   
  7.   private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {   
  8.       is.defaultReadObject();//java对象反序列化默认操作   
  9.       int x=is.readInt();   
  10.       int y=is.readInt();   
  11.       super.init(x,y);   
  12.   }  

writeObject和readObject方法为JVM会在序列化和反序列化java对象时会分别调用的两个方法,修饰符都是private,没错。

我们在序列化的默认动作之后将超类里的两个值域x和y也写入object流;与之对应在反序列化的默认操作之后读入x和y两个值,然后调用超类的初始化方法。

再次执行程序之后的输出为:

Java代码

 
 
 
  1. x:10;y:50  
  2. z:100  
  3. x:10;y:50  
  4. z:100  

另外还有两个自定义序列化方法writeReplace和readResolve,分别用来在序列化之前替换序列化对象 和 在反序列化之后的对返回对象的处理。一般可以用来避免singleTon对象跨jvm序列化和反序列化时产生多个对象实例,事实上singleTon的对象一旦可序列化,它就不能保证singleTon了。JVM的Enum实现里就是重写了readResolve方法,由JVM保证Enum的值都是singleTon的,所以建议多使用Enum代替使用writeReplace和readResolve方法。

Java代码

 
 
 
  1. private Object readResolve()   
  2.     {   
  3.         return INSTANCE;   
  4.     }   
  5.       
  6.     private Object writeReplace(){   
  7.         return INSTANCE;   
  8.     }  

注:writeReplace调用在writeObject前;readResolve调用在readObject之后。

文章名称:Java自定义序列化行为解析
文章分享:http://www.shufengxianlan.com/qtweb/news5/489855.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联