您的位置:首页 > 编程语言 > Java开发

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 序列化 分布式