java序列化理解_Java序列化理解与总结

本文详细介绍了Java对象序列化,包括其定义、应用场景、代码示例以及注意事项。Java序列化允许在内存中的对象状态被保存到文件或数据库,或在网络中传递。在反序列化时,能恢复对象的状态。序列化适用于持久化对象、RMI和网络传输。文章还提到了transient关键字的作用,序列化时静态变量不会被保存,以及序列化ID和存储规则的问题。同时,强调了在序列化和反序列化过程中对象的顺序和版本一致性的重要性。
摘要由CSDN通过智能技术生成

1、什么是Java序列化

Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。

使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。

除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。

2、Java序列化的应用场景

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;

当你想用套接字在网络上传送对象的时候;

当你想通过RMI传输对象的时候;

3、代码实例

public class Box implements Serializable{

private int width;

private int height;

public Box(int width, int height) {

this.width = width;

this.height = height;

}

public int getWidth() {

return width;

}

public void setWidth(int width) {

this.width = width;

}

public int getHeight() {

return height;

}

public void setHeight(int height) {

this.height = height;

}

@Override

public String toString() {

return "Child{" +

"width=" + width +

", height=" + height +

'}';

}

}

测试

public class SerializableTest {

public static void main(String args[]) throws Exception{

File file = new File("box.out");

FileOutputStream fos = new FileOutputStream(file);

ObjectOutputStream out = new ObjectOutputStream(fos);

Box oldBox = new Box(10,20);

out.writeObject(oldBox);

out.close();

FileInputStream fis = new FileInputStream(file);

ObjectInputStream in = new ObjectInputStream(fis);

Box newBox = (Box)in.readObject();

in.close();

System.out.println(newBox.toString());

}

}

输出结果:

Child{width=10, height=20}

4、基本知识点

Serializable接口

对于任何需要被序列化的对象,都必须要实现接口Serializable,它只是一个标识接口,本身没有任何成员,只是用来标识说明当前的实现类的对象可以被序列化.

如果父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。

如果被写对象的类型是String,或数组,或Enum,或Serializable,那么就可以对该对象进行序列化,否则将抛出NotSerializableException。

对象的读写

Java类中对象的序列化工作是通过 ObjectOutputStream和 ObjectInputStream来完成的。

使用readObject()|writeObject()方法对对象进行读写操作;对于基本类型,可以使用readInt()|writeInt(), readDouble()|writeDouble()等类似的接口进行读写。

transient关键字

如果某实例变量不能或不应该被序列化,就把它标记为 transient的变量,这样序列化程序就会把它跳过。

transient的引用变量会以 null返回,基本数据类型会以相应的默认值返回。

(例如:引用类型没有实现Serializable,或者动态数据只可以在执行时求出而不能或不必存储)

5、注意事项

读取对象的顺序必须与写入的顺序相同;

如果有不能被序列化的对象,执行期间就会抛出 NotSerializableException异常;

序列化时,只对对象的状态进行保存,而不管对象的方法;

静态变量不会被序列化,因为所有的对象共享同一份静态变量的值;

如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存还原,而且会是递归的方式。 (序列化程序会将对象版图上的所有东西储存下来,这样才能让该对象 恢复到原来的状态)

如果子类实现Serializable接口而父类未实现时,父类不会被序列化,但此时父类必须有个 无参构造方法,否则会抛InvalidClassException异常;

因为反序列化时会恢复原有子对象的状态,而父类的成员变量也是原有子对象的一部分。由于父类没有实现序列化接口,即使没有显示调用,也会默认执行父类的无参构造函数使变量初始化;

6、深入理解

(1).序列化算法透析

Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。

序列化算法一般会按步骤做如下事情:

◆将对象实例相关类的描述。

◆递归地输出类的超类描述直到不再有超类。

◆从最顶层的超类开始输出对象实例的实际数据值。

详细介绍

(2).序列化ID的问题

serialVersionUID适用于JAVA的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。

在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。

详细示例

(3).序列化存储规则

Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用;

序列化到同一个文件时,如第二次修改了相同对象属性值再次保存时候,虚拟机根据引用关系知道已经有一个相同对象已经写入文件,因此只保存第二次写的引用,所以读取时,都是第一次保存的对象。

详细介绍

(4).多次序列化的问题

在一次的序列化的过程中,ObjectOutputStream 会在文件开始的地方写入一个 Header 的信息到文件中。于是在多次序列化的过程中就会继续在文件末尾(本次序列化的开头)写入 Header 的信息,这时如果进行反序列化的对象的时候会报错:

java.io.StreamCorruptedException: invalid type code: AC

解决方法

(5).影响序列化

◆transient关键字

◆writeObject()方法与readObject()方法

◆Externalizable接口

◆readResolve()方法

详细介绍

作者:u013670933 发表于2015/7/27 14:44:49 原文链接

阅读:94 评论:0 查看评论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>