Java序列化
2015-07-18 10:06
609 查看
java序列化
序列化的作用
java序列化是把对象持久化, 将对象写入流或者文件中,以便网络传输远程对象,或者将对象的状态持久化。反序列化是将对象的状态读出重建承一个对象的过程。序列化的必要性
java中一切都是对象,在分布式环境中,经常需要将对象从一端的网络或设备移动到另一端,这就需要两端定义传输协议,java序列化就是为了解决这个问题而产生的。如何序列化
实现序列化的对象必须实现serializable接口,该接口没有任何方法,只是一个仅用于标识可序列化的语义。接口定义为:
public interface Serializable
例:
import java.io.Serializable; public class Student implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String Stu_no; private String Stu_name; private int age; public Student(){ } public Student(String Stu_no,String Stu_name,int age){ this.age = age; this.Stu_name = Stu_name; this.Stu_no = Stu_no; } public String getStu_no() { return Stu_no; } public void setStu_no(String stu_no) { Stu_no = stu_no; } public String getStu_name() { return Stu_name; } public void setStu_name(String stu_name) { Stu_name = stu_name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
然后我们生成一个Student的对象,将对象写入到文件中
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class TestSeria { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub Student stu = new Student("12072125","Amiy",19); FileOutputStream out = new FileOutputStream("D:\\amiy.out"); ObjectOutputStream obout = new ObjectOutputStream(out); obout.writeObject(stu); obout.flush(); obout.close(); } }以下是将持久的文件中读取重建新对象:
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class TestSeria { /** * @param args * @throws IOException * @throws ClassNotFoundException */ public static void main(String[] args) throws IOException, ClassNotFoundException { // TODO Auto-generated method stub //Student stu = new Student("12072125","Amiy",19); FileInputStream out = new FileInputStream("D:\\amiy.out"); ObjectInputStream obout = new ObjectInputStream(out); Student Jimy = (Student) obout.readObject(); } }
对象的序列化格式
上图是生成的Aimy.out文件通过notepad++以16进制的格式打开的
ac ed 是序列化协议
00 05 是序列化的版本号
73声明是一个新对象
72声明这里开始是一个新类
72 00class名字的长度
后面的大家也可以推理出来
序列化算法
通过java序列化,可以实现对象的克隆
java序列化安全问题
因为对象对象序列化后的格式几乎是可以识别的对象在网上传输的过程中容易出现安全性问题,java提供了一个安全机制,序列化允许 “hook” 序列化过程,并在序列化之前和反序列化之后保护(或模糊化)字段数据。可以通过在Serializable对象上提供一个
writeObject方法来做到这一点。
模糊化序列化数据
假设Student类中的敏感数据是age 字段。毕竟,女士忌谈年龄。 我们可以在序列化之前模糊化该数据,将数位循环左移一位,然后在反序列化之后复位。(您可以开发更安全的算法,当前这个算法只是作为一个例子。)
为了 “hook” 序列化过程,我们将在Student上实现一个
writeObject方法;为了
“hook” 反序列化过程,我们将在同一个类上实现一个
readObject方法。重要的是这两个方法的细节要正确
— 如果访问修改方法、参数或名称的内容,那么代码将不被察觉地失败,Student的
age 将暴露。
private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException { // "Encrypt"/obscure the sensitive data age = age << 2; stream.defaultWriteObject(); } private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException { stream.defaultReadObject(); // "Decrypt"/de-obscure the sensitive data age = age << 2; }
序列化的数据可以被签名和密封
上一个技巧假设您想模糊化序列化数据,而不是对其加密或者确保它不被修改。当然,通过使用 writeObject和
readObject可以实现密码加密和签名管理,但其实还有更好的方式。
如果需要对整个对象进行加密和签名,最简单的是将它放在一个
javax.crypto.SealedObject和/或
java.security.SignedObject包装器中。两者都是可序列化的,所以将对象包装在
SealedObject中可以围绕原对象创建一种
“包装盒”。必须有对称密钥才能解密,而且密钥必须单独管理。同样,也可以将
SignedObject用于数据验证,并且对称密钥也必须单独管理。
结合使用这两种对象,便可以轻松地对序列化数据进行密封和签名,而不必强调关于数字签名验证或加密的细节。
transient关键字
只要在可被序列化的域的前面声明该关键字,此域将不会被序列化,有些域的值只是暂时的,如内存地址、时间等,序列化后不可用的时候,需要将该域声明为transient
探讨serialVersionUID
在上文中,我们描述序列化原理时,曾经提及每个对象都会有一个唯一的序列号,这个序列号,就是serialVersionUID。当我们的对象实现Serializable接口时,该接口可以为我们生成serialVersionUID。
有两种方式来生成serialVersionUID,一种是固定值:1L,一种是经过JVM计算,不同的JVM采取的计算算法可能不同。
下面就是两个serialVersionUID的示例:
1 private static final long serialVersionUID = 1L; 2 private static final long serialVersionUID = -2380764581294638541L;
第一行是采用固定值生成的;第二行是JVM经过计算得出的。
那么serialVersionUID还有其他用途吗?
我们可以使用它来控制版本兼容。如果采用JVM生成的方式,我们可以看到,当我们业务对象的代码保持不变时,多次生成的serialVersionUID也是不变的,当我们对属性进行修改时,重新生成的serialVersionUID会发生变化,当我们对方法进行修改时,serialVersionUID不变。这也从另一个侧面说明,序列化是作用于对象属性上的。
当我们先定义了业务对象,然后对其示例进行了“序列化”,这时根据业务需求,我们修改了业务对象,那么之前“序列化”后的内容还能经过“反序列化”返回到系统中吗?这取决于业务对象是否定义了serialVersionUID,如果定义了,那么是可以返回的,如果没有定义,会抛出异常。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统