笔记:I/O流-对象序列化

Java
语言支持一种称为对象序列化(Object
Serialization)的非常通用的机制,可以将任何对象写入到流中,并在之后将其读回,首先需要支持对象序列化的类,必须继承与
Serializable
接口,该接口没有任何方法,只是对类起到标记的作用,然后使用
ObjectOutputStream
流来序列化对象,使用
ObjectInputStream
流来反序列化,示例代码如下:

  • 对象类声明:

    public class Employee implements Serializable {

    ????????private String name;

    ????????private String sex;

    ????????public
    Employee() {

    ????????}

    ????????public
    Employee(String name, String sex) {

    ????????????????this.name = name;

    ????????????????this.sex = sex;

    ????????}

    ????????// getter 和 setter 方法

    }

    ?
    ?

    public class Manager extends Employee {

    ????????private Employee secretary;

    ????????public
    Manager(){

    ????????}

    ????????public
    Manager(String name, String sex) {

    ????????????????super(name, sex);

    ????????}

    ????????// getter 和 setter 方法

    }

  • 创建对象实例:

    ?Employee harry = new
    Employee("Harry Hacker", "男");

    ?Manager boss = new
    Manager("Carl Cracker", "女");

    boss.setSecretary(harry);

  • 序列化到文件

    ?
    ObjectOutputStream outputStream = null;

    ?????????try {

    ???????????????
    outputStream = new
    ObjectOutputStream(new
    FileOutputStream("serializableApp.dat"));

    ????????????????outputStream.writeObject(boss);

    ????????
    } catch (FileNotFoundException ex) {

    ????????????????ex.printStackTrace();

    ????????
    ?} finally {

    ????????????????if (outputStream != null) {

    ???????????????????????outputStream.close();

    ????????????????}

    ???????
    ?}

  • 从文件反序列化

????????????????ObjectInputStream inputStream = null;

????????????????try {

????????????????????????inputStream = new
ObjectInputStream(new
FileInputStream("serializableApp.dat"));

????????????????????????Manager serializableBoss = (Manager) inputStream.readObject();

????????????????????????System.out.println("manager name is " + serializableBoss.getName() + " sex is "

????????????????????????????????????????+ serializableBoss.getSex() + " secretary is "

????????????????????????????????????????+ serializableBoss.getSecretary().getName());

????????????????} catch (ClassNotFoundException ex) {

????????????????????????ex.printStackTrace();

????????????????} catch (FileNotFoundException ex) {

????????????????????????ex.printStackTrace();

????????????????} finally {

????????????????????????if (inputStream != null) {

????????????????????????????????inputStream.close();

????????????????????????}

????????????????}

每个对象都用一个序列号保存的,对象序列化机制如下:

  • 对于遇到的每一个对象引用都关联一个序列号
  • 对于每一个对象,当第一次遇到时,保存器对象数据到流中
  • 如果某个对象已经被保存过,那么只写出保存的序列号
  • 对于流中的对象,在第一次遇到其序列号时,创建他,并使用流中数据来初始化他,然后记录这个顺序号和新对象之间的关联
  • 当遇到对象引用另一个对象的序列号时,获取与这个序列号相关联的对象引用

某些数据域时不可以序列化的,例如,只对本地方法有意义的存储文件句柄或窗口句柄的整数值等,Java
拥有一种简单的机制来防止这种域被序列化,那就是将他们标记成
transient,如果被标记为不可序列化的类,也需要将其标记为
transient,瞬时域在对象序列化时总是被跳过,示例如下:

????private transient Point2D.Double point;

?
?

  1. 修改默认的序列化机制

    序列化机制单个的类提供了一种方式,去向默认的读写行为添加验证或任何其他想要的行为,可序列化类可以定义具体有如下签名的方法:

    ????????private
    void
    readObject(ObjectInputStream in)

    ????????????????????????throws IOException,ClassNotFoundException;

    ????????
    ?

    ????????private
    void
    writeObject(ObjectOutputStream out)

    ????????????????????????throws IOException;

    readObject

    writeObject
    方法只需要保存和加载本类的数据域,而不需要关注基类(超类)数据和任何其他类的信息,实现给方法的具体示例如下:

    ???? private
    void
    readObject(ObjectInputStream in)

    ????????????????????????throws IOException, ClassNotFoundException {

    ????????????????// 读取序列化字段数据

    ????????????????in.defaultReadObject();

    ????????????????// 其他数据校验或者序列化

    ????????}

    ????????private
    void
    writeObject(ObjectOutputStream out)

    ????????????????????????throws IOException{

    ????????????????// 写入序列化字段数据

    ????????????????out.defaultWriteObject();

    ????????????????// 其他数据校验或者序列化

    ???????}

    除了可以使用readObject

    writeObject方法来保存和恢复对象数据外,类还可以定义他自己的机制,类需要实现
    Externalizable
    接口,该接口定义了两个方法:

    ????public
    void
    readExternal(ObjectInput in)

    ????????
    throws IOException, ClassNotFoundException;

    ?
    ?

    ????public
    void
    writeExternal(ObjectOutput out)

    ????????????throws IOException ;

    这些方法对包括超类数据在内的整个对象的存储和恢复负全责,而序列化机制在流中仅仅只是记录该对象所属的类,示例代码如下:

  • 基类代码:

    ????????public
    void
    writeExternal(ObjectOutput out) throws IOException {

    ????????????????out.writeUTF(this.name);

    ????????????????out.writeUTF(this.sex);

    ????????}

    ????????public
    void
    readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    ????????????????this.name = in.readUTF();

    ????????????????this.sex = in.readUTF();

    ????????}

  • 子类代码:

    @Override

    public
    void
    readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    ????????super.readExternal(in);

    ????????this.secretary = new
    Employee();

    ???????
    this.secretary.readExternal(in);

    ?}

    @Override

    public
    void
    writeExternal(ObjectOutput out) throws IOException {

    ????????super.writeExternal(out);

    ???????this.secretary.writeExternal(out);

    ?}

    ?
    ?

  1. 序列化单例和类型安全的枚举

    在序列化和反序列化时,如果目标对象时唯一的,使用默认的序列化机制时不适用的,因为默认的序列化机制,即使构造器时私有的,序列化机制也可以创建新的对象,因此在进行==(比较)时将失败,为了解决整个问题需要定义一个名称为 readResolve的特殊方法,在对象被序列化之后就会调用他,返回一个对象,而该对象之后会称为 readObject 的返回值,示例代码如下:

    public class Orientation implements Serializable {

    ????????public static final Orientation HORIZONTAL = new
    Orientation(1);

    ????????public static final Orientation VERTICAL = new
    Orientation(2);

    ?
    ?

    ????????private
    int value;

    ?
    ?

    ????????private
    Orientation(int value) {

    ????????????????this.value = value;

    ????????}

    ?
    ?

    ????????protected Object readResolve() throws ObjectStreamException {

    ????????????????if (value == 1) {

    ????????????????????????return HORIZONTAL;

    ????????????????}

    ????????????????if (value == 2) {

    ????????????????????????return VERTICAL;

    ????????????????}

    ????????????????
    ?

    ????????????????return null;

    ????????}

    }

  2. 版本管理

    无论类的定义产生了什么样的变化,他的SHA指纹也会跟着变化,而我们知道对象流拒绝读入具有不同指纹的对象,但是,类可以表明他对其早期版本保持兼容,在类的所有较新的版本都必须把
    serialVersionUID
    常量定义与最初版本的指纹相同,如果一个类具有名为
    serialVersionUID
    的静态数据成员,就不需要在人工的计算其指纹,而只需直接使用整个值,示例如下:

    public class Employee implements Serializable, Externalizable {

    ????????public static final
    long serialVersionUID = -2349238498234324L;

    }

    如果类只有方法产生了变化,那么在读入新对象数据时是不会有任何问题的,如果是数据域产生了变化,那么就可能会有问题,常见情况如下:

  • 如果数据域之间名字匹配而类型不匹配,那么对象流不会进行类型转换,因此不兼容
  • 如果流中的对象具有当前版本中所没有的数据域,那么对象流会忽视这些额外的数据
  • 如果当前版本具有在流化对象中所没有的数据域,那么这些新增加的域将被设置成他们的默认值(对象是null、数字为
    0,布尔类型为
    false)

?
?

时间: 2024-10-12 14:09:43

笔记:I/O流-对象序列化的相关文章

疯狂Java学习笔记(56)------------对象序列化

所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象! 对象序列化是对象持久化的一种实现方法,它是将一个对象的属性和方法转化为一种序列化的格式以用于存储和传输,反序列化就是根据这些保存的信息重建对象的过程. java对象序列化机制一般来讲有两种用途: 1.需要将对象的状态保存到文件中(存储),而后能够通过读入对象状态来重新构造对象,恢复程序状态 2.使用套接字在网络上传送对象的程序来说,是很有用的(传输). 我们通过让类实现java.io.Serializable

JAVA笔记12__字节、字符缓冲流/打印流/对象流/

/** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * BufferedInputStream:字节缓冲流(有一个内部缓冲区数组,用于缓冲数据) */ public class Main { public static void main(String[] args) { input(); output(); } /** * 使用字节缓冲流进行读取操作

JAVA基础学习day22--IO流四-对象序列化、管道流、RandomAccessFile、DataStream、ByteArrayStream、转换流的字符编码

一.对象序列化 1.1.对象序列化 被操作的对象需要实现Serializable接口 1.2.对象序列化流ObjectOutputStream与ObjectInputStream ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化. ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的

对象流--对象的序列化

1.对象是存在于内存中的(堆内存),有时候我们需要将对象保存在硬盘上,又有时我们需要将对象保存在另一台计算机上等等这样的操作, 这时候我们需要将对象转化为一个字节序列,而这个过程就是对象的序列化,相反我么又这样一个字节序列需要将其转化为对应的对象, 这个过程就是对象的反序列化. 2.对象-----序列化---字节序列 字节序列---反序列化---对象 3.使用OOS实现对象的序列化------ObjectOutputStream是用来对对象进行序列化的输出流, 其实现对象序列化的方法为:  -v

黑马程序猿——25,打印流,合并流,对象序列化,管道流,RandomAccessFile

------<ahref="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 黑马程序猿--25.打印流.合并流.对象序列化,管道流,RandomAccessFile /* IO流的打印流:专门用于打印的流 字节打印流PrintStream PrintStream的构造函数能够接收file对象,String型字符串路

Java—IO流 对象的序列化和反序列化

序列化的基本操作 1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中: 反序列化流(ObjectInputStream),readObject 方法用于从输入流中读取对象. 3.序列化接口(Serializeable) 对象必须实现序列化接口,才能进行序列化,否则会出现异常.这个接口没有任何方法,只是一个标准. package com.test.io; import

动车上的书摘-java对象流与序列化

动车上的书摘-java对象流与序列化 摘要: 摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 钢笔不限贵便宜,书法是来自心对手的交流.-泥沙砖瓦浆木匠 一.对象序列化 当需要存储相同类型的数据,选择固定的长度记录是好选择.但是在面向对象(OOP)程序中,对象之间很少有全部相同的类型.所以,java语言支持一种称为对象序列化(object serialization)的机制. 下面展示一个序列化例子,关于两个对象 Em

Thinking in java 琐碎知识点之 I/O流 、对象序列化

Java I/O流 .对象序列化 1.File类 此类的实例可能表示(也可能不表示)实际文件系统对象,如文件或目录. File类可以新建.删除和重命名文件和目录,但是File不能访问文件本身的内容,这要使用IO流. File对象的createNewFile()方法在磁盘上创建真实的文件 例程:FileTest.java import java.io.*; public class FileTest { public static void main(String[] args) throws I

疯狂Java学习笔记(84)----------关于 Java 对象序列化您不知道的 5 件事

数年前,当和一个软件团队一起用 Java 语言编写一个应用程序时,我体会到比一般程序员多知道一点关于 Java 对象序列化的知识所带来的好处. 关于本系列 您觉得自己懂 Java 编程?事实上,大多数程序员对于 Java 平台都是浅尝则止,只学习了足以完成手头上任务的知识而已.在本 系列 中,Ted Neward 深入挖掘 Java 平台的核心功能,揭示一些鲜为人知的事实,帮助您解决最棘手的编程挑战. 大约一年前,一个负责管理应用程序所有用户设置的开发人员,决定将用户设置存储在一个 Hashta