序列化和反序列化
序列化:将对象当前状态转换为字节序列,并通过输出流存储或传输的过程
作用:将对象转换成输出流,永久保存或传输
条件:被序列化的对象的类,实现Serializable接口或Externalizable接口
实例一:
package serializable.s1;
import java.io.Serializable;
/**
* 用于创建被序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class Son implements Serializable {
// 年龄
public int age;
// 颜值
public int faceValue;
// 构造方法
public Son(int age, int faceValue) {
this.age = age;
this.faceValue = faceValue;
}
// 重写父类(Object类)的toString方法
@Override
public String toString() {
return "age = " + age + "\nfaceValue = " + faceValue;
}
}
package serializable.s1;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* 序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class SerializableObject {
public static void main(String[] args) {
//创建一个对象son
Son son = new Son(18);
//声明文件输出流的引用
FileOutputStream fos = null;
//声明对象输出流的引用
ObjectOutputStream oos = null;
try {
//创建文件输出流的对象,其中文件的后缀名可以自定义
fos = new FileOutputStream("E:\\son.txt");
//创建对象输出流的对象
oos = new ObjectOutputStream(fos);
//将对象写入文件,序列化之后son的age值应为20
oos.writeObject(son);
System.out.println("序列化完成!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
//关闭对象输出流
oos.close();
}
if (fos != null) {
//关闭文件输出流
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化:将序列化产生的字节序列,通过输入流读取,并恢复成对象的过程
package serializable.s1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* 反序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class RecoveryObject {
public static void main(String[] args) {
Son son = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
//创建文件输入流对象,这里的文件路径要和序列化时的一致
fis = new FileInputStream("E:\\son.txt");
ois = new ObjectInputStream(fis);
//从对象输入流中读取对象,并强制转换为Son类型
son = (Son) ois.readObject();
//输出
System.out.println(son.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(ois != null){
//关闭对象输入流
ois.close();
}
if (fis != null) {
//关闭文件输入流
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果:
age = 18
faceValue = 250
注意:在序列化之后,如果对Son类进行了修改,而没有重新执行序列化操作;此时进行反序列化会出现InvalidClassException(无效的类型异常);
这是因为在序列化时,会给对象加上一个默认的版本号,这个版本号由各属性名,方法名等计算得出;在反序列化时,会验证序列化时产生的版本号,和当前类的版本号是否一致,如果不一致就会产生InvalidClassException
static final long serialVersionUID属性:序列化版本号
作用:用于反序列化时,验证反序列化的对象和当前类是否是同一版本
序列化版本号,可以自己写,也可以使用编译器自动生成的。
自己写这个版本号时要注意,只能写成static final long serialVersionUID这样的,版本号的值可以自定义。
使用Eclipse自动生成,如下图
当设定了版本号,在序列化之后,只要不修改类名和版本号,对类的其他修改,不会使反序列化出现InvalidClassException。
实例二:
package serializable.s2;
import java.io.Serializable;
/**
* 用于创建被序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class Son implements Serializable {
/**
* 编译器自动生成的序列化版本号
*/
private static final long serialVersionUID = 5430359291175859046L;
public int age;
//将实例一的Son类,增加版本号并执行序列化后,将属性faceValue该为fV在执行反序列化
public int fV;
//增加name属性
String name;
public Son(int age, int faceValue) {
this.age = age;
this.fV = faceValue;
}
@Override
public String toString() {
//增加name的输出
return "age = " + age + "\nfV = " + fV + "\nname = " + name;
}
}
运行结果:
age = 18
fV = 0
name = null
由结果可以看到,被修改和新增的属性值,均为属性的数据类型的默认值。可以理解为删除了faceValue属性,而新增了属性fV和name;反序列化无法获取这些新增属性的值,因为序列化时还没有它们,所以这些属性的值为默认值
关键字transient
使用关键字transient修饰的属性,不会被序列化
实例三:
package serializable.s3;
import java.io.Serializable;
/**
* 用于创建被序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class Son implements Serializable {
public int age;
//将实例一Son中的faceValue属性加上关键字transient修饰
public transient int faceValue;
public Son(int age, int faceValue) {
this.age = age;
this.faceValue = faceValue;
}
@Override
public String toString() {
return "age = " + age + "\nfaceValue = " + faceValue;
}
}
运行结果:
age = 18
faceValue = 0
faceValue的值为0,并不是250;这就是因为使用关键字transient修饰的属性,不会被序列化
序列化父类
使Son类继承Father类
实例四:
package serializable.s4;
import java.io.Serializable;
/**
* 用于创建被序列化对象的类,继承Father类
* @author 学霸联盟 - 赵灿
*/
public class Son extends Father implements Serializable {
public int age;
public int faceValue;
public Son(int age, int faceValue) {
this.age = age;
this.faceValue = faceValue;
//对从Father类继承的money属性赋值
this.money = 200;
}
@Override
public String toString() {
return "age = " + age + "\nfaceValue = " + faceValue + "\nmoney = "
+ money;
}
}
package serializable.s4;
public class Father{
public int money;
}
运行结果:
age = 18
faceValue = 250
money = 0
package serializable.s4;
import java.io.Serializable;
//增加Father类对Serializable接口的实现
public class Father implements Serializable {
public int money;
}
运行结果:
age = 18
faceValue = 250
money = 200
引用类型的属性
Son类中增加一个Friend类型的属性
实例五:
package serializable.s5;
import java.io.Serializable;
/**
* 用于创建被序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class Son implements Serializable {
public int age;
public int faceValue;
//增加Friend属性
public Friend friend;
public Son(int age, int faceValue) {
this.age = age;
this.faceValue = faceValue;
//创建Friend对象
friend = new Friend();
friend.name = "张三";
}
@Override
public String toString() {
return "age = " + age + "\nfaceValue = " + faceValue + "\nfriendName = " + friend.name;
}
}
package serializable.s5;
public class Friend{
public String name;
}
执行序列化操作时会出现NotSerializableException
package serializable.s5;
import java.io.Serializable;
//增加Friend类对Serializable接口的实现
public class Friend implements Serializable{
public String name;
}
运行结果:
age = 18
faceValue = 250
friendName = 张三
String类,数组,枚举都实现了Serializable接口,所以可以直接使用
自定义序列化
将实例五的Son该为实现Externalizable接口
实例六:
package serializable.s6;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* 用于创建被序列化对象的类
* @author 学霸联盟 - 赵灿
*/
public class Son implements Externalizable {
public int age;
public transient int faceValue;
public Friend friend;
//必须包含public的无参构造方法,否则会出现InvalidClassException
public Son() { }
public Son(int age, int faceValue) {
this.age = age;
this.faceValue = faceValue;
//创建Friend对象
friend = new Friend();
friend.name = "张三";
}
/**
* 重写Externalizable接口中定义的方法
* 向输出流中写属性值
*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
//向输出流中写入属性age和faceValue的值
out.writeInt(age);
out.writeInt(faceValue);
}
/**
* 重写Externalizable接口中定义的方法
* 读取输入流中的属性值,并赋值给相应的属性
* 这里要注意,读属性值的顺序要和写属性值的顺序一致
*/
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
//从输入流中读取age和faceValue的值,并赋值给相应的属性
age = in.readInt();
faceValue = in.readInt();
}
@Override
public String toString() {
return "age = " + age + "\nfaceValue = " + faceValue;
}
}
package serializable.s6;
public class Friend{
public String name;
}
输出结果:
age = 18
faceValue = 250
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化示例代码.rar
学霸教育网站整站源码说明:由sdcms管理系统制作模板而来,请尊重原创。 后台地址:http://你的域名/iszxwadmin/ 管理账号:admin 密码:admin 学霸教育网站整站源码介绍: 本程序适合个人门户站、学校管理...
奥拉夫·舍韦的这本《超级学霸》就是教你如何开出正确的药方,来根治“学习不好”的病。 舍韦本来是一名天资平平、成绩中下的普通挪威学生,因为掌握了正确的学习方法,从普通学生一跃变成了超级学霸,成功考取了...
ASP.NET中序列化与反序列化-以显示上一次登录的信息示例代码
明明白白学Java大学霸
学霸快查助手是一款记录学习过程中的知识点,学习时能够快速查阅的学习软件,可以随时随地记录知识点,随时随地的快速查阅知识点,学霸快查软件就是专为学霸而生,提高学习效率,有需要的赶快下载吧! 学霸快查...
系统集成项目管理工程师-学霸一本通
学霸脑图--理科
测验记录:详细地记录了学生在“基础测试”、“阶段小考”各个知识点出现的错误,可以使学生在任意时间调用,以“温故而知新”,也为“智能化出题”,“对症下药”提供基础。 四、练 “练”对“测”中发现的问题...
我的钢笔是“学霸”
学霸课堂是一款学生课堂学习软件。软件包含:幼儿启蒙教育、小学、初中、高中 全部基本课程,基本课程为人教版。 学霸课堂软件特点 1:名校名师课堂讲解,够生动够详细,学生易掌握学习要点。 2:学习内容全面,除了...
二年级(下)语文学霸期末测评卷12套
学霸经验分享:高三政治学习心得.docx
学霸经验分享:高三政治学习心得.pdf
学霸经验分享:高三政治学习心得.doc
学霸直男主题错题本.pdf
一年高分过三科,中级会计学霸告诉你怎么学[001].pdf
用户:面向所有爱好学习又有一定自律能力的人,学霸会真正的理解这款软件的用意和需求,希望更多人成为学霸。(只是提醒功能,并没有必要禁止你上网,因为你总有办法停止或卸载软件) 安装好了,马上去自习室感觉...
使用SolidWorks2018进行的100个.SLDPRT建模文件。适用于初学者的学习,可以详细查看每一步操作的细节。