1. 什么是Serializable接口?

当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何方法),表示该类可以被序列化。

序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列, 可以将该字节序列保存起来(如:保存在一个文件中),以后可以随时将该字节序列恢复为原来的对象。甚至可以将该字节序列放到其他计算机上或者通过网络传输到其他计算机上恢复,只要该计算机平台存在相应的类。

2. 如何实现?

首先创建一个OutputStream对象,然后将其封装在一个ObjectOutputStream对象内,再调用writeObject()方法即可序列化一个对象。反序列化也类似。

 import java.io.*; 

 public class Person implements Serializable {
private String userName;
private String password; public Person(String userName, String password) {
this.userName = userName;
this.password = password;
} public String toString() {
return "userName:" + userName + " password:" + password;
} public static void main(String[] args)
throws FileNotFoundException, IOException, ClassNotFoundException { //序列化一个对象(存储到一个文件)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));
oos.writeObject("Save a object:\n");
oos.writeObject(new Person("Bruce", "123456"));
oos.close(); //反序列化,将该对象恢复(存储到一个文件)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));
String s = (String)ois.readObject();
Person p = (Person)ois.readObject();
System.out.println(s + p); //序列化一个对象(存储到字节数组)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos2 = new ObjectOutputStream(baos);
oos2.writeObject("Save another object:\n");
oos2.writeObject(new Person("Phil", "654321"));
oos2.close(); //反序列化,将该对象恢复(存储到字节数组)
ObjectInputStream ois2 = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
s = (String)ois2.readObject();
p = (Person)ois2.readObject();
System.out.println(s + p);
}
}

输出信息:

Save a object:
userName:Bruce password:123456
Save another object:
userName:Phil password:654321

3. transient关键字:

1)引入原因:自动序列化将对象所有的字段都持久化了,有的时候需要对某些字段不进行持久化(例如:密码,因为序列化后会暴露密码),所以我们使用transient关键字让Serializable对象某些字段不被序列化。

2)操作:

public class Person implements Serializable{
private String userName; // 不序列化password——因为序列化后会暴露密码
private transient String password;
}

加入transient关键字后,上面程序的运行结果:

Save a object:
userName:Bruce password:null
Save another object:
userName:Phil password:null

3)如果想要控制序列化字段,使得被transient修饰的字段也能被序列化:有两种方法

1. 手动序列化,添加两个私有的方法:writeObject(),readObject()

 import java.io.*; 

 public class Person implements Serializable {
private String userName;
private transient String password; public Person(String userName, String password) {
this.userName = userName;
this.password = password;
} public String toString() {
return "userName:" + userName + " password:" + password;
} private void writeObject(ObjectOutputStream out) throws IOException {
//序列化所有非transient字段,必须是该方法的第一个操作
out.defaultWriteObject(); //序列化transient字段
out.writeObject(password);
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//反序列化所有非transient字段,必须是该方法的第一个操作
in.defaultReadObject(); //反序列化transient字段
password = (String)in.readObject();
} public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//序列化一个对象(存储到一个文件)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));
oos.writeObject("Save a object:\n");
oos.writeObject(new Person("Bruce", "123456"));
oos.close(); //反序列化,将该对象恢复(存储到一个文件)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));
String s = (String)ois.readObject();
Person p = (Person)ois.readObject();
System.out.println(s + p);
}
}

输出结果:

Save a object:
userName:David password:13579

2. 使用Externalizable接口替代Serializable接口。

  • 此时需要定义一个默认的构造器,否则将会得到一个异常:(java.io.InvalidClassException: Person; Person; no valid constructor);
  • 还需要定义两个方法(writeExternal()和readExternal())来控制要序列化的字段
 import java.io.*; 

 //使用Externalizable接口代替Serializable接口
public class Person implements Externalizable {
private String userName;
private String password; // 需要一个默认的构造器,否则得到一个异常
public Person() {
System.out.println("default constructor invoked!");
} public Person(String userName, String password) {
this.userName = userName;
this.password = password;
} public String toString() {
return "userName:" + userName + " password:" + password;
} public void writeExternal(ObjectOutput out) throws IOException {
//序列化字段
out.writeObject(userName);
out.writeObject(password);
} public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//反序列化字段
userName = (String)in.readObject();
password = (String)in.readObject();
} public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
/ /序列化一个对象(存储到一个文件)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.out"));
oos.writeObject("Save a object:\n");
oos.writeObject(new Person("Leo", "1984"));
oos.close(); //反序列化,将该对象恢复(存储到一个文件)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.out"));
String s = (String)ois.readObject();
Person p = (Person)ois.readObject();
System.out.println(s + p);
}
}

得到结果如下:

default constructor invoked!
Save a object:
userName:Leo password:1984

注意:

以上方式只能恢复成Java对象,如果想要恢复成其他对象(如C++对象),那就要将Java对象转换为XML格式,这样可以使其被各种平台和各种语言使用。可以使用随JDK一起发布的javax.xam.*类库,或者使用开源XOM类库(可以从www.xom.nu下载并获得文档)。

Serializable接口和transient关键字的更多相关文章

  1. Java中的Serializable接口和transient关键字

    Java中的Serializable接口和transient关键字 Table of Contents 1. 向memcached中放数据时遇到NotSerializableException异常 2 ...

  2. Java中的实体类--Serializable接口、transient 关键字

    在java中,实体类是一个非常重要的概念,我们可以在实体类中封装对象.设置其属性和方法等.关于实体类,也经常涉及到适配器模式.装饰者模式等设计模式.那么在实际代码开发中,关于实体类的注意事项有哪些呢? ...

  3. Java的transient关键字

    Java的transient关键字   Java 中的 transient 关键字被用来表示变量将不被序列化处理.那么在理解 transient 关键字之前,我们先了解下什么是序列化. 什么是序列化 ...

  4. Java Serializable的使用和transient关键字使用小记(转载)

    一:Serializable 1.持久化的简单介绍: “持久化”意味着对象的“生存时间”并不取决于程序是否正在执行——它存在或“生存”于程序的每一次调用之间.通过序列化一个对象,将其写入磁盘,以后在程 ...

  5. transient关键字的用法

    本篇博客转自 一直在路上 Java transient关键字使用小记 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java ...

  6. Java transient关键字使用小记

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...

  7. Java transient关键字序列化时使用小记

    1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...

  8. Java 序列化 transient关键字

    Java 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. tra ...

  9. (转)Java transient关键字使用小记

    背景:最近在看java底层的源码实现,看到一个关键字,不是很熟悉,专门做个记录. 原文出处:http://www.importnew.com/21517.html#comment-637072 哎,虽 ...

随机推荐

  1. SQL Server 2008 R2企业版开发版等版本下载 (转载)

    一. 简体中文 1. SQL Server 2008 R2 Developer (x86, x64, ia64) - DVD (Chinese-Simplified) File Name: cn_sq ...

  2. PlayerPrefs游戏存档

    本地存储.相当于Flash里面的SharedObject. Android位置:机器自身存储的(非扩展卡)/data/data/appname/shared_prefs/{AppName}.xml,如 ...

  3. 预装WIN8系统的电脑安装WIN7的方法

    前些天,给一位客户的本本安装WIN7,因为原来预装了WIN8,结果按常规方法安装一直没有成功,不管是光盘还U盘.所以心里一直有个疑问,所以留意查阅了有关资料和相关的文章,终于明白了问题所在,现在在这里 ...

  4. 详解rsync算法--如何减少同步文件时的网络传输量

    先看下图中的场景,客户端A和B,以及服务器server都保存了同一个文件,最初,A.B和server上的文件内容都是相同的(记为File.1).某一时刻,B修改了文件内容,上传到SERVER上(记为F ...

  5. Tiny6410 LCD设置

    1.注意LCD的硬件连接 2.LCD初始化 2.1 初始化步骤 LCD时序设置 LCD芯片 2.2 引脚初始化 2.3 配置 MIFPCON 寄存器及SPCON 寄存器 2.4 配置VIDCONx 2 ...

  6. 《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第四章内容. 1.函数:通过函数可以封装 ...

  7. python脚本基础总结

    1. 注释 ①单行注释:#单行注释 ②多行注释: ''' 三个单引号,多行注释符 ''' ③中文注释:#coding=utf-8 或者 #coding=gbk 2.输入输出 ① 输入:  3.0后的p ...

  8. Spark Streaming中动态Batch Size实现初探

    本期内容 : BatchDuration与 Process Time 动态Batch Size Spark Streaming中有很多算子,是否每一个算子都是预期中的类似线性规律的时间消耗呢? 例如: ...

  9. FileInputStream、FileReader、FileInputStream、FileWriter使用小结

    本文是基于Linux环境运行,读者阅读前需要具备一定Linux知识 InputStream包含如下三个方法: int read():从输入流中读取单个字节,返回所读取的字节数据(字节数据可直接转化为i ...

  10. VMware 虚拟机桥接网络设置

    一.桥接的基本原理    配置成桥接网络连接模式的虚拟机就当作主机所在以太网的一部分,虚拟系统和宿主机器的关系,就像连接在同一个Hub上的两台电脑,可以像主机一样可以访问以太网中的所有共享资源和网络连 ...