关于Java的序列化的文章在网上已经够多了,在这里写关于Java序列化的文章是对自己关于这方面的的一种总结,结合以前的开发经验与网上的资料,写了这篇文章,对自己是有着巩固记忆的作用,也希望能够对大家有一定帮助。

一、什么是序列化(Serialization)?

  序列化是Java提供的一种机制,将对象转化成字节序列,在字节序列中保存了对象的数据、对象的类型的信息与存储在对象中的数据的类型。序列化实际上就是将保存对象的"状态",可以方便以后的程序使用或者通过网络传输到另一台主机使用。一般来说,对象的生成周期取决于程序是否在执行,而序列化能够将对象保存在磁盘或网络中,这样对象就能生存在程序的调用之间。

二、序列化的目的

  用序列化来保存对象的状态,主要是为了支持两大特性:

  1. Java的远程方法调用(RMI),它能够存活于其他机器上的对象使用起来就像存活于本地一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。
  2. 在Java Beans中,必须使用对象序列化。

三、序列化基本实例

  Java中实现序列化最基本的方法是实现Serializable接口,Serializable接口是标记接口,不包含任何方法。要序列化一个对象,必须先创建某些OutoutStream对象,然后封装到ObjectOutputStream对象内,其中ObjectOutputStream提供writeObject()方法,调用该方法即可将对象序列化。

  反序列化是指将对象序列化生成的字节序列还原成对象,需要将InputStream对象封装在ObjectInputStream对象中,然后调用readObject即可读出对象。

  下面是对象序列化的基本实例:

class Pet implements Serializable {
private String name; public Pet(String name) {
this.name = name;
} public String toString() {
return name;
}
} public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private int age;
private String name;
private Pet ownPet; public Person(String name, int age, Pet ownPet) {
this.name = name;
this.age = age;
this.ownPet = ownPet;
} @Override
public String toString() {
return "Person [age=" + age + ", name=" + name + ", ownPet=" + ownPet
+ "]";
} public static void main(String[] args) throws FileNotFoundException,
IOException, ClassNotFoundException {
Person p1 = new Person("person1 ", 47, new Pet("dog"));
Person p2 = new Person("person2 ", 34, new Pet("cat"));
// 对象序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
"person.out"));
System.out.println("Save objects:");
out.writeObject(p1);
out.writeObject(p2);
out.close(); // 对象反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"person.out"));
System.out.println("Recovering objects:");
p1 = (Person) in.readObject();
p2 = (Person) in.readObject();
System.out.println(p1);
System.out.println(p2);
}
}

  上述程序结果是:

Save objects:
Recovering objects:
Person [age=47, name=person1 , ownPet=dog]
Person [age=34, name=person2 , ownPet=cat]

  从上面的结果看出,对象序列化不仅将调用writeObject()的对象序列化,而且通过追踪调用writeObject()的对象的引用,并保存那些引用的对象,所以对象序列化能够自动保存对象的相关引用对象,能够保证对象信息的完整性,因此能够使用对象序列化进行对象的深度复制。

  注意事项:实现Serializable接口对象反序列化并没有调用构造器,是直接将字节序列还原成对象。在序列化过程中必须保证classpath中必须有该类,在本实例即Person.class,否则抛出ClassNotFoundException。

三、实现Externalizable接口

  序列化的另一种方法是实现Externalizable接口,Externalizable接口提供以下默认方法:

    void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

  用户必须使用自己实现这两个方法,在方法中可以控制序列化,如可以让一些成员属性不进行序列化,实例如下:

public class Test implements Externalizable {

    private int i;
private String s; public Test() {
System.out.println("Test default constructor");
} public Test(String x, int a) {
System.out.println("Test(String x, int a)");
s = x;
i = a;
} public String toString() {
return s + i;
} public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Blip3.writeExternal");
// You must do this:
out.writeObject(s);
out.writeInt(i);
} public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
System.out.println("Blip3.readExternal");
// You must do this:
s = (String) in.readObject();
i = in.readInt();
} public static void main(String[] args) throws FileNotFoundException,
IOException, ClassNotFoundException {
System.out.println("Constructorint objects:");
Test test = new Test("A String ", 47);
System.out.println(b3);
// 对象序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
"test.out"));
System.out.println("Save objects:");
out.writeObject(b3);
out.close(); // 对象反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"test.out"));
System.out.println("Recovering test:");
b3 = (Test) in.readObject();
}
}

  上述程序运行结果为:

Constructorint objects:
Test(String x, int a)
A String 47
Save objects:
Test.writeExternal
Recovering test:
Test default constructor
Test.readExternal

  从结果中能够看出为了能实现对象的序列化,不仅必须在writeExternal()方法中写入对象成员变量,而且要在readExternal()方法中读取成员变量。在对象的反序列化过程中调用了默认的构造方法。

四、transient关键词

  transient能够对成员变量进行控制,防止敏感信息泄漏,当然上面的实现Externalizable的方法也可以完成该功能,但是必须自己控制所有的属性进行序列化,比较复杂。而采用transient(瞬时)关键词就能关闭该字段的序列化,如下实例所示:

public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password; public Logon(String name, String password) {
this.username = name;
this.password = password;
} public String toString() {
return "Logon info: \n username: " + username + "\n date: " + date
+ "\n password: " + password;
} public static void main(String[] args) throws FileNotFoundException,
IOException, ClassNotFoundException {
Logon a = new Logon("Hulk", "myLittlePony");
System.out.println("logon a =" + a);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
"out/Logon.out"));
o.writeObject(a);
o.close(); // 获取序列化的数据
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"out/Logon.out"));
System.out.println("Recovering object at " + new Date());
a = (Logon) in.readObject();
System.out.println("logon a =" + a);
}
}

  上述程序的结果为:

logon a = Logon info:
username: Hulk
date: Wed Jan 20 21:55:16 CST 2016
password: myLittlePony
Recovering object at Wed Jan 20 21:55:16 CST 2016
logon a = Logon info:
username: Hulk
date: Wed Jan 20 21:55:16 CST 2016
password: null

  从结果中,可知对password字段进行了隐藏,没有进行序列化。

五、代替实现Externalizable

  在对象序列化过程中对序列化控制,如果采用实现Externalizable接口的方式,必须实现每一个属性的序列化控制,太过复杂,那如何替代它呢?通过实现Serializable接口并添加两个方法,只要提供这两个方法,就会使用它们而不是默认的序列化机制。这两个方法签名如下所示:

  private void writeObject(ObjectOutputStream stream) throws IOException

  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException   

  在上面两个方法中能够调用默认的处理方法,也可以自己控制属性的序列化,实例代码如下:

public class SerialCtl implements Serializable {
private String a;
private transient String b; public SerialCtl(String aa, String bb) {
this.a = "Not trnsient: " + aa;
this.b = "Transient: " + bb;
} public String toString() {
return a + "\n" + b;
} private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeObject(b);
} private void readObject(ObjectInputStream stream) throws IOException,
ClassNotFoundException {
stream.defaultReadObject();
b = (String) stream.readObject();
} public static void main(String[] args) throws FileNotFoundException,
IOException, ClassNotFoundException {
SerialCtl sc = new SerialCtl("Test1", "Test2");
System.out.println("Before:\n " + sc);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(buf);
o.writeObject(sc);
// 获取序列化的数据
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(
buf.toByteArray()));
sc = (SerialCtl) in.readObject();
System.out.println("After:\n " + sc);
}
}

  上述程序的结果:

Before:
Not trnsient: Test1
Transient: Test2
After:
Not trnsient: Test1
Transient: Test2

六、总结

  综上所述,最简单的序列化就是实现Serializable接口,如果为了敏感信息的安全,可以使用transient关键字。如果想近一步控制序列化过程,建议实现Serializable接口并添加两个序列化方法,并自定义实现方法。

Java序列化(Serialization)的更多相关文章

  1. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  2. 各种Java序列化性能比较

    转载:http://www.jdon.com/concurrent/serialization.html 这里比较Java对象序列化 XML JSON  Kryo  POF等序列化性能比较. 很多人以 ...

  3. Java序列化格式详解

    RPC的世界,由于涉及到进程间网络远程通信,不可避免的需要将信息序列化后在网络间传送,序列化有两大流派: 文本和二进制. 文本序列化 序列化的实现有很多方式,在异构系统中最常用的就是定义成人类可读的文 ...

  4. 编解码-java序列化

    大多数Java程序员接触到的第一种序列化或者编解码技术就是Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够通过j ...

  5. java序列化---转

    Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是 ...

  6. Java序列化的机制和原理

    Java序列化的机制和原理 本文讲解了Java序列化的机制和原理.从文中你可以了解如何序列化一个对象,什么时候需要序列化以及Java序列化的算法. 有关Java对象的序列化和反序列化也算是Java基础 ...

  7. Java 序列化Serializable详解(附详细例子)

    Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化 Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization ...

  8. Java 序列化 JDK序列化总结

    Java 序列化 JDK序列化总结 @author ixenos Java序列化是在JDK 1.1中引入的,是Java内核的重要特性之一.Java序列化API允许我们将一个对象转换为流,并通过网络发送 ...

  9. JAVA序列化与反序列化三种格式存取(默认格式、XML格式、JSON格式)

    什么是序列化 java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输.或者持久化存储到数据库或文件系统中:然后在需要的时候 ...

随机推荐

  1. setTimeout/setInterval伪异步

    setTimeout(function(){alert(1);}, 1000); 在使用setTimeout.setInterval的时候,会传一个时间来控制代码的执行时机.在经过了设置的时间段后,代 ...

  2. Codeforces Round #375 (Div. 2)E. One-Way Reform

    题目链接:传送门 题目大意:一副无向图,要求你给边定向(变为有向图),使出度等于入度的点最多,输出有多少 个点,并且输出定向后的边(前为起点,后为终点) 题目思路:欧拉路 我们这样考虑,先考虑无向图的 ...

  3. JQuery中$.ajax()方法参数详解 转载

    url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 ...

  4. 1.node.js下载

    1.下载node.js http://nodejs.cn/ 2.下载git https://git-scm.com/download/win 3.安装npm npm install npm -g 使用 ...

  5. JSTL的一些使用规范,坑

    三目表达式要加空格不然有些服务器解析不了 var maxBanners = ${maxBanners==null ? 3 : maxBanners}; forEach循环的长度正确使用方式 <c ...

  6. 【转载】keil(MDK-ARM)的调试使用

    现在软件的模拟功能都是非常强大,但是有时候会用不好. 原文地址: 那就看这里吧:http://www.cnblogs.com/strongerHuang/p/5596355.html 1.编译+调试 ...

  7. Spring Security使用心得

    某天,你的客户提出这样一个需求,在点击购买商品的时,如果用户没有注册,并且用户没有账号,这时用户去创建账户,然后要直接返回到想购买商品的付款页面.你会该如何基于Spring Security实现? S ...

  8. 七夕节---hdu1215(打表求因子和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1215 给你一个数n(1<=n<=50w)求n的所有因子和, 由于n的范围比较大,所以要采用 ...

  9. 【转发】Python使用openpyxl读写excel文件

    Python使用openpyxl读写excel文件 这是一个第三方库,可以处理xlsx格式的Excel文件.pip install openpyxl安装.如果使用Aanconda,应该自带了. 读取E ...

  10. Python-装饰器-案例-获取文件列表

    import os def get_all_path(fun): '''装饰器.功能:获取全路径文件名.如:D:/tmp/12.txt :param fun: :return:file_path_li ...