ObjectStreamDemo

简介: 当你需要存储相同类型的数据时,使用固定长度的记录格式是一个不错的选择。但,在OOP中创建的对象很少全部都具有相同的类型。 例如,你可能有一个称为staff(见下面demo)的array,它名义上是一个Employee记录数组,但是实际上却包含诸如Manager这样的子类实例。

 

当你需要存储相同类型的数据时,使用固定长度的记录格式是一个不错的选择。但,在OOP中创建的对象很少全部都具有相同的类型。

例如,你可能有一个称为staff(见下面demo)的array,它名义上是一个Employee记录数组,但是实际上却包含诸如Manager这样的子类实例。

为解决这个问题,当然可以设计出一种数据格式来存储这种多态集合,但由于有序列化,设计这种类型是没有必要的。
Java语言支持一种称为对象序列化(Object serialization)的非常通用的机制,它可以将任何对象写出到流中,并在之后将其读回。

如果需要对象流中存储或恢复的所有类都进行一下修改,这些类必须实现Serializable接口;
Serializable接口没有任何方法,与Cloneable接口很相似。

只有在写出对象时才能用writeObject/readObject方法,对于基本类型值,需要使用诸如writeInt/readInt或writeDouble/readDouble这样的方法。对象流类都实现了DataInput/DataOutput接口。

由于对象引用而形成的对象网络,Object Serialization不能去保存和恢复对象的地址,因为当对象被重新加载时,JVM为对象分配的内存地址与在另一个JVM中分配的不同。
Object Serialization在处理的办法是使用序列号(serial number):
每个对象都是用一个序列号保存。由于序列化使用序列号代码内存地址,所以允许将对象集合从一台机器传送到另一台机器。正是由于序列号的使用,这种机制被称为对象序列化。
其算法如下:
(1)对遇到的每一个对象引用都关联一个序列号
(2)对于每个对象,当第一次遇到时,保存其对象数据到流中
(3)如果某个对象之前已经被保存过,那么只写出“与之前保存过的序列号为x的对象相同”;在读回对象时,整个过程是反过来的
(4)对于流中的对象,在第一次遇到其序列号时,构建它,并使用流中数据来初始化它,然后记录这个顺序号和新对象之间的关联
(5)当遇到“与之前保存过的序列号为x的对象相同”标记时,获取与这从此顺序号相关联的对象引用


例外的处理:
某些数据域永远都不应该被序列化,例如,只对本地访问有意义的存储文件句柄或窗口句柄的整数值,这种信息在稍后重新加载对象或将其传送到其他机器上时都是没有用处的。事实上,这种域的值如果不恰当,还会引起本地方法崩溃。
Java有一种很简单的机制来防止这种域被序列化,那就是将这些域使用transient关键字来修饰。如果这些域属于不可序列化的类,使用transient关键字修饰即可。瞬时的域在对象被序列化时问题被跳过的。
例如java.awt.geom包中有大量类都是不可能序列化的,例如Point2D.Double,在对象定义使用private transient Point2D.Double point;这样就可以避免NotSerializableException;

在序列化和反序列化对象被认为是惟一时,需要对枚举值做特殊处理。唯一的对象,譬如单例和类型安全的枚举

    protected Object readResolve() {
        if (value==1) {
            return Orientation.HORIZONTAL;
        }else if (value==2) {
            return Orientation.VERITAL;
        }
        return null;
    }

 

package io.serial;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.GregorianCalendar;

/*2015-7-9*/
public class ObjectStreamTest {
    public static void main(String[] args) {
        Employee harry = new Employee("Tom", 20000, 2015, 7, 10);
        Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);
        carl.setSecretary(harry);
        Manager tony = new Manager("Tony Tester", 40000, 1990, 3, 15);
        tony.setSecretary(harry);

        Employee[] staff = new Employee[3];
        staff[0] = harry;
        staff[1] = carl;
        staff[2] = tony;

        try {
            String fileName = "employee.dat";
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
            out.writeObject(staff);
            out.close();

            ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
            Employee[] newStaff = (Employee[]) in.readObject();
            for (Employee employee : newStaff) {
                System.out.println(employee);
            }
            in.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

}

class Employee implements Serializable {
    private static final long serialVersionUID = -167978670073609475L;
    private String name;
    private double salary;
    private Date hireDay;

    public Employee(String name, double salary, int year, int month, int dayOfMonth) {
        super();
        this.name = name;
        this.salary = salary;
        GregorianCalendar calendar = new GregorianCalendar(year, month - 1, dayOfMonth);
        this.hireDay = calendar.getTime();
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public Date getHireDay() {
        return hireDay;
    }

    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }

    @Override
    public String toString() {
        return getClass().getName() + " [name=" + name + ", salary=" + salary + ", hireDay=" + hireDay + "]";
    }

}

class Manager extends Employee {
    private static final long serialVersionUID = -668252664793507835L;
    private Employee secretary;

    public Manager(String name, double salary, int year, int month, int dayOfMonth) {
        super(name, salary, year, month, dayOfMonth);
    }

    public void setSecretary(Employee secretary) {
        this.secretary = secretary;
    }

    @Override
    public String toString() {
        return super.toString() + " [secretary=" + secretary + "]";
    }
}


Output:

io.serial.Employee [name=Tom, salary=20000.0, hireDay=Fri Jul 10 00:00:00 CST 2015]
io.serial.Manager [name=Carl Cracker, salary=80000.0, hireDay=Tue Dec 15 00:00:00 CST 1987] [secretary=io.serial.Employee [name=Tom, salary=20000.0, hireDay=Fri Jul 10 00:00:00 CST 2015]]
io.serial.Manager [name=Tony Tester, salary=40000.0, hireDay=Thu Mar 15 00:00:00 CST 1990] [secretary=io.serial.Employee [name=Tom, salary=20000.0, hireDay=Fri Jul 10 00:00:00 CST 2015]]

 

相关文章
|
人工智能 达摩院 算法
AI顶会论文解读 | 达摩院榜首人脸检测模型MogFace
AI顶会论文解读 | 达摩院榜首人脸检测模型MogFace
|
Python
python编程-22:BeautifulSoup库入门
python编程-22:BeautifulSoup库入门
106 0
python编程-22:BeautifulSoup库入门
|
弹性计算 Java Linux
我的ECS使用体验
分享一下我最近使用ECS的体验报告
|
CDN
全民加速节:夏日看球丝般顺滑 阿里云CDN为你加速
今晚没有什么比一场酣畅淋漓的球赛更美妙。但是,在视频平台直播看球也有痛点,那就是“卡顿”和“延时”。看看这对邻居看「球赛直播」的时候,到底发生了什么?
1482 0
全民加速节:夏日看球丝般顺滑 阿里云CDN为你加速
|
物联网 运维 传感器
|
机器学习/深度学习 Java 大数据
像数据科学家一样思考:12步指南(中)
数据科学家思维到底是什么样的?这篇文章告诉你!文中可获得免费电子书地址!
1896 0
|
C#
使用WPF实现3D场景[二]
原文:使用WPF实现3D场景[二] 在上一篇的文章里我们知道如何构造一个简单的三维场景,这次的课程我将和大家一起来研究如何用代码,完成对建立好了的三维场景的观察。
1137 0
|
关系型数据库 Linux PHP