本文为原创文章,欢迎转载,但请注明出处http://www.cnblogs.com/yexiubiao/p/5014015.html,未在文章页面明显位置给出原文连接的,将保留追究法律责任的权利。

通过java的ObjectOutputStream、ObjectInputStream类能对实现了Serializable接口的对象实现序列化与反序列化,如下

import java.io.Serializable;

import com.alibaba.fastjson.JSON;

public class Person implements Serializable{
private static final long serialVersionUID = 1L; private int id;
private String name; public Person() {
super();
} public Person(int id, String name) {
super();
this.id = id;
this.name = name;
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
} @Override
public String toString() {
          // 这里偷懒用了Fastjson
return JSON.toJSONString(this);
}
}

  

序列化(写入对象):

反序列化(读取对象)

通过这样就能把一个对象存入磁盘里,并且能读取到内存里

以上是Serializable的基本用法,接下来介绍一些使用中的小细节(关于以下出现的术语,保存对象与序列化,读取对象与反序列化都分别是同一个意思)。

1,将对象序列化到本地后,对类进行修改,增加或减少字段(成员变量)或交换字段位置,然后反序列化之前保存的对象,都不会报错。

例如去掉id字段并增加newValue字段:

此时能正常读取之前序列化的对象(newValue字段因为值是null,这里默认不展示):

2,改变serialVersionUID值后,读取时发生异常

 java.io.InvalidClassException: com.ye.test.model.Movie; Incompatible class (SUID): com.ye.test.model.Movie: static final long serialVersionUID =1L; but expected com.ye.test.model.Movie: static final long serialVersionUID =2L;
因为serialVersionUID值改变后,类定义的版本变化了,所以读取老版本对象将可能不兼容新对象,因此系统抛出异常
读取为null:
 
3,保存的时候对象有serialVersionUID,然后删除这个字段,再次读取
则读取时serialVersionUID会被赋值一个自动生成的值

这个值根据类的成员变量方法定义等算出,增减成员变量或者增减方法都会导致这个值的改变
但是如果增加空格,交换成员变量位置等都不会导致这个值被改变
java.io.InvalidClassException: com.ye.test.model.Movie; Incompatible class (SUID): com.ye.test.model.Movie: static final long serialVersionUID =1L; but expected com.ye.test.model.Movie: static final long serialVersionUID =-6926675519878447654L;
也就是说,如果我们的Person类没有声明serialVersionUID变量,则以后这个类只要涉及到增减成员变量或者增减方法都会导致读取对象时不兼容。当然方法位置的调整不会影响。
 
4,如果先序列化保存一个对象到磁盘,然后修改这个类的定义,将其继承至一个基类(基类没有实现Serializable接口),则会报错

 java.io.InvalidClassException: com.ye.test.model.BaseMovie; IllegalAccessException
at java.io.ObjectStreamClass.resolveConstructorClass(ObjectStreamClass.java:692)
如果基类实现了Serializable接口,则能正常读取
 
5,如果基类已经实现了Serializable接口,则子类无需再次实现(当然子类再次实现也没关系)
 
6,父类的serialVersionUID成员变量对子类没有影响,即使他是public的,所以反序列化时能不能兼容只会跟子类的serialVersionUID对象数值相关。
也就是说开发中如果我们定义的类已经修改,需要告诉系统我们的类已经不再兼容老版本,则需要修改子类的serialVersionUID版本号而不是父类。
 
7,如果子类实现Serializable接口,父类没有实现,则只可以执行序列化,不能执行反序列化,执行反序列化时报错信息同4
 
总结:
1,如果存在继承关系,则只需在基类实现Serializable接口即可
2,serialVersionUID变量需在子类定义,父类定义没有意义(父类定义serialVersionUID用来消除编译警告信息也没关系)
3,如果没有定义serialVersionUID变量,则系统在保存或读取时会根据类结构自动算出一个值赋予serialVersionUID,如果类结构没有变化,那么这个值则是固定的,所以还是尽量使用自定义的值比较便于维护。
4,如果需求变更导致类结构调整,那么如果需要继续读取老版本对象的话, 则不要修改serialVersionUID的版本号,如果需要使用全新的数据而抛弃之前保存在磁盘里的对象,则修改serialVersionUID版本号,系统会默认读取为null。相当于之前没有保存过。
 
最后附上demo,有兴趣的话可以自己测试下。

Java里Serializable的那些事的更多相关文章

  1. Java你可能不知道的事(3)HashMap

    概述 HashMap对于做Java的小伙伴来说太熟悉了.估计你们每天都在使用它.它为什么叫做HashMap?它的内部是怎么实现的呢?为什么我们使用的时候很多情况都是用String作为它的key呢?带着 ...

  2. java你可能不知道的事(2)--堆和栈

    在java语言的学习和使用当中你可能已经了解或者知道堆和栈,但是你可能没有完全的理解它们.今天我们就一起来学习堆.栈的特点以及它们的区别.认识了这个之后,你可能对java有更深的理解. Java堆内存 ...

  3. java中serializable

    java中serializable是一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的.因此如果要序列化某些类的对象,这些类就必须实现Serializable接 ...

  4. Java里的IO流里的 ObjectInputStream 的读取\写入!

    各位好!!我又来了!!今天遇见了一个小问题!! IO流里的对象读取总是出错!各种报错!!神烦啊!!百思不得其解啊!然后就上网百度!找了好久终于让我找到了!下面就让我来说一说! 当你用IO流里的对象流写 ...

  5. java基础---->Serializable的使用

    本次讲解中我们建立一个Java的项目去体会一下序列化Serializable的使用,序列化的原理以及序列化的自定义请参见我的另外一篇博客(java高级---->Serializable序列化的源 ...

  6. java你可能不知道的事(2)--堆和栈<转>

    在java语言的学习和使用当中你可能已经了解或者知道堆和栈,但是你可能没有完全的理解它们.今天我们就一起来学习堆.栈的特点以及它们的区别.认识了这个之后,你可能对java有更深的理解. Java堆内存 ...

  7. Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

    遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题a,什么叫序列化和反序列化b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化c,seria ...

  8. Java 序列化Serializable具体解释(附具体样例)

    Java 序列化Serializable具体解释(附具体样例) 1.什么是序列化和反序列化 Serialization(序列化)是一种将对象以一连串的字节描写叙述的过程:反序列化deserializa ...

  9. [转]Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

    原文地址:https://blog.csdn.net/qq_27093465/article/details/78544505 遇到这个 Java Serializable 序列化这个接口,我们可能会 ...

随机推荐

  1. SQL_Server_2008修改sa密码的方法

    转载自:http://blog.csdn.net/templar1000/article/details/20211191 1. 先用Window身份验证方式登陆进去,选择数据库实例,右键选择属性—— ...

  2. oracle 卸载和安装

    第一步:在“服务”窗口中停止与oracle有关的所有服务 第二步:卸载Oracle软件 “所有程序——oracle 安装目录——oracle 安装产品——Universal Installer” 第三 ...

  3. js按钮浮动随手指方向移动而移动

    window.document.getElementById("moveDIV").addEventListener("touchmove", function ...

  4. 处理 Oracle SQL in 超过1000 的解决方案

    处理oracle sql 语句in子句中(where id in (1, 2, ..., 1000, 1001)),如果子句中超过1000项就会报错.这主要是oracle考虑性能问题做的限制.如果要解 ...

  5. cpp项目的组织

    编译篇 较大型cpp项目的代码组织.编译都是深耦合的. 一般提供一个总体的makefile,进入各个模块,又有自己的makefile,这些makefile又都依赖于一些被include的文件的的定义, ...

  6. js动态更改对象属性值的方法

    下面代码,替换属性名称包含date的属性中的T为空格. for (var o in data) {                        //console.info(eval("d ...

  7. 【耐克】【空军一号 Nike Air Force 1】【软木塞】

     [高帮 全白 36-45] [空军一号 低帮 36-46] [空军一号 36-45] [Nike Air Force 1 Flyknit 空军中帮飞线系列 全黑 36-44] [耐克空军一号 软木塞 ...

  8. android development

    1. Supporting different devices 1) Supporting different screen size 主要有几点,首先是布局文件夹以及布局文件的命名 layout/m ...

  9. WebAPI学习点滴(二)

    刚开始学习WebApi就遇到了问题,在同一个API控制器中,如果两个方法的签名相同,比如 [HttpGet] public string GetString() { return "Hell ...

  10. Java 使用Memcache

    使用spymemcached.jar public class MemcachedJava { public static void main(String[] args) { try { // 连接 ...