网站首页 > java教程 正文
前言
对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象。对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这种二进制流(无论是从磁盘中获取的,还是通过网络获取的),都可以将这种二进制流恢复成原来的Java对象
序列化的含义和意义
序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以备以后重新恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
对象的序列化(Serialize)指将一个Java对象写入IO流中,与此对应的是,对象的反序列化 (Deserizlize)则指从IO流中恢复该Java对象。
对象序列化方式
如果需要让某个对象支持序列化机制,则必须让它的类是可序列化的。为了让某个类可序列化,该类必须实现以下两个接口之一。
Serializable
Externalizable
使用Serializable来实现序列化非常简单,主要让目标类实现Serializable标记接口即可,无须实现任何方法。一旦某个类实现了Serializable 接口,该类的对象就是可序列化的。
对象引用的序列化
如果某个类的成员变量的类型不是基本类型或String类型,而是另一个引用类型,那么这个引用类必须是可序列化的,否则拥有该类型成员变量的类也是不可序列化的。
对像序列化算法
- 所有保存到磁盘中的对象都有一个序列化编号
- 当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列化过,只有该对象从未(在本次虚拟机中)被序列化过,系统才会将该对象转换成字节序列并输出。
- 如果某个对象己经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象。
自定义序列化
在一些特殊的场景下,如果一个类里包含的某些实例变量是敏感信息,例如个人电话号码信息等,这时不希望系统将该实例变量值进行序列化,或者某个实例变量的类型是不可序列化的,因此不希望对该实例变量进行递归序列化,以避免引发异常
java.io.NotSerializableException异常。通过在实例变量前面使用transient关键字修饰,可以指定Java序列化时无须理会该实例变量。
使用transient关键字修饰实例变量虽然简单、方便,但被transient修饰的实例变量将被完全隔离在序列化机制之外,这样导致在反序列化恢复Java对象时无法取得该实例变量值。Java还提供了一种自定义序列化机制,通过这种自定义序列化机制可以让程序控制如何序列化各实例变量,甚至完全不序列化某些实例变量(与使用transient关键字的效果相同)
在序列化和反序列化过程中需要特殊处理的类应该提供如下特殊签名的方法, 这些特殊的方法用以实现自定义序列化
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
}
private void readObjectNoData() throws ObjectStreamException {
}
另一种序列化机制
Java还提供了另一种序列化机制,这种序列化方式完全由程序员决定存储和恢复对象数据。要实现该目标,Java类必须实现Externalizable接口,该接又里定义了如下两个方法
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
readExternal()方法来实现反序列化
writeExternal()方法来实现序列化
两种序列化的对比
实现Serializable接口 | 实现Externalizable接口 |
系统自动存储必要信息 | 程序员决定存储哪些信息 |
java内建支持,易于实现,只需实现该接口即可,无须任何代码 | 仅仅提供两个空方法,实现该接口必须为两个空方法提供实现 |
性能略差 | 性能略好 |
版本
反序列化Java对象时必须提供该对象的class文件,现在的问题是,随着项目的升级,系统的class文件也会升级,Java如何保证两个class文件的兼容性?
Java序列化机制允许为序列化类提供一个private static final的serialVersionUID值,该类变量的值用于标识该Java类的序列化版本,也就是说,如果一个类升级后,只要它的serialVersionUID类变量值保持不变,序列化机制也会把它们当成同一个序列化版本。
如果不显式定义serialVersionUID类变量的值,该类变量的值将由JVM根据类的相关信息计算,而修改后的类的计算结果与修改前的类的计算结果往往不同,从而造成对象的反序列化因为类版本不兼容而失败。
猜你喜欢
- 2025-06-13 这款可视化的对象存储服务真香!Github标星28K+
- 2025-06-13 「设计模式」原型模式:如何快速的克隆出一个对象?
- 2025-06-13 Java原型模式详解:从克隆技术到实战应用
- 2025-06-13 Java反射的奇妙应用(java反射的奇妙应用是什么)
- 2025-06-13 《Java培训:解锁面向对象思想的核心密码》
- 2025-06-13 Python学不会来打我(5)深拷贝和浅拷贝详解
- 2025-06-13 Java对象序列化与反序列化的那些事
- 2025-06-13 性能瓶颈诊断:如何揪出 Dubbo 大对象传输这个“幕后黑手”?
- 2025-06-13 如何理解 Java的值传递和引用传递
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)