本文为原创文章,欢迎转载,但请注明出处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. lua userdata

    #define metatablename "studentlib.06-11-11" /** * utility functions */ static int pusherro ...

  2. C#中as用法

    在程序中,进行类型转换时常见的事,C#支持基本的强制类型转换方法,例如 Object obj1 = new NewType();NewType newValue = (NewType)obj1;这样强 ...

  3. sdk 简单说明文档草稿。

    SDK初始化: HighApi为SDK核心类,请客户端持有其唯一单例对API进行调用. HighApi构造器函数 HighApi(Context appContext, final String ap ...

  4. Binary Tree Inorder Traversal

    Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary tre ...

  5. linux文件系统节点详解

    linux文件系统有两层结构,逻辑结构和物理结构.也就是inode和block. 每个文件都有一个inode, 记录文件属性:权限,时间还有最重要的block号码. block是实际存放文件内容的地方 ...

  6. C# 实现软件的重启

    有些时候我们想用户在设置完之后使程序重新启动生效,这时候我们只需要简单的应用一下代码即可: if (MessageBox.Show("设置保存成功,下次启动时生效,是否马上重启软件?&quo ...

  7. 关于js代码中与或运算符||&&的妙用

    看bootstrap时看到如下一行JavaScript代码产生了疑惑. return window.pageYOffset || e.scrollTop ||在这里的作用是什么呢? 首先明确概念,在j ...

  8. COCOS2D-X中UI动画导致闪退与UI动画浅析

    前两天和同事一起查一个游戏的闪退问题,log日志显示最后挂在CCNode* ActionNode::getActionNode()函数中的首行CCNode* cNode = dynamic_cast& ...

  9. 王爽<<汇编语言>> 实验十四

    ;以"年/月/日 时:分:秒"的格式, 显示当前的日期, 时间 assume cs:code code segment main: out 70h,al ;告诉CMOS RAM将要 ...

  10. maven项目导入tomcat7源码

    大家好,今天给大家分享对于tomcat源码在eclipse上的导入运行.此次为以tomcat7为例. 1去官网tomcat7的下载页面下载源码网址http://tomcat.apache.org/do ...