• Java IO(六) ObjectInputStream 和 ObjectOutputStream


    Java IO(六) ObjectInputStream 和 ObjectOutputStream

    一、介绍

    对于对象数据的处理,Java IO 提供了 ObjectInputStream 和 ObjectOutputStream 来序列化和反序列对象数据。

    ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久性存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

    (一)、ObjectInputStream

    创建输出流对应的 ObjectOutputStream 对象,该ObjectOutputStream对象能提供对基本数据或对象的持久性存储。

    (二)、ObjectOutputStream

    当我们需要读取这些存储的基本数据或对象时,可以创建输入流对应的 ObjectInputStream,进而读取出这些基本数据或对象。如果流是网络套接字流,则可以在另一台主机上或另一个进程中反序列化对象。

    注意: 只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能被 ObjectInputStream / ObjectOutputStream 所操作!

    二、序列化与反序列化

    Java是一种完全面向对象的高级语言,所以在编写程序的时候数据大都存放在对象当中。我们有时会需要将内存中的整个对象都写入到文件中去,然后在适当的时候再从文件中将对象还原至内存。我们可以使用ObjectInputStream 和 ObjectOutputStream 类来完成这个任务。

    (一)、序列化和反序列化概念

    列化是指将对象的状态信息转换为可以存储或传输的形式(2进制数据)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

    (二)、序列化和反序列化的特点

    • 永久保存对象。将对象的字节序列保存到文件中。
    • 通过序列化可以在网络中传递对象数据。
    • 通过序列化可以在进程中传递对象数据。

    (三)、序列化与反序列化过程

    (四)、serialVersionUID  

    在对象进行序列化或者反序列化操作的时候,要考虑序列化版本的问题,如果序列化的版本和反序列化的J版本不统一则就可能造成异常,所以在序列化操作中引入了一个serialVersionUID的常量,可以通过此常量来验证版本的一致性,在进行反序列化时,JVM会将传过来的字节流中的serialVersionUID与本地相应实体的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就抛出不一致的异常。

    (五)、序列化了哪些数据呢

    所有的对象拥有各自的属性值,但是所有的方法都是公共的,所以序列化对象的时候实际上序列化的就是属性。

    注意,当我们想要向一个已经存在的文件中追加对象时,应该重写ObjectOutputStream的writeStreamHeader()方法,并空实现。因为,ObjectOutputStream在写入数据的时候会加上一个特别的流头(Stream Header),在读取数据的时候会先检查这个流头。所以我们在向文件中追加对象的时候ObjectOutputStream就会再次向文件中写入流头,这样在读取对象的时候会发生StreamCorrupedException异常。

    (六)、Serializable 接口和 Externalizable 接口

    1、Serivlizable接口

    Serializable接口仅仅定义了接口,里面并没有代码实现,只作为标识,如果一个自定义类实现了 Serializable 接口,说明此类是可以序列化的。

    2、Externalizable 接口

    如果现在用户希望可以自己制定序列化的内容,则可以让自定义类实现 Externalizable 接口,然后分别实现 public void writeExternal(ObjectOutput out) 和  public void readExternal(ObjectInput in) 方法。

    3、Externalizable 和 Serializable接口区别

    • 实现复杂度。Serializable实现简单,Java对其有支持;Externalizable复杂,需要程序员分别实现 public void writeExternal(ObjectOutput out) 和  public void readExternal(ObjectInput in) 方法。
    • 执行效率。Serializable 中所有对象数据有Java保存,效率高;Externalizable 中对象数据有开发者保存,效率较低。
    • 保存空间。Serializable 中所有对象数据都会保存,占用空间大;Externalizable 中保存对象数据由开发者决定,保存空间可大可小。

    (七)、transient 关键字

    在序列化操作的时候,如果某个属性不希望被序列化,则可以直接使用 transient 关键字声明。

    三、构造方法

    (一)、ObjectInputStream

    (二)、ObjectOutputStream

    四、常用API

    (一)、ObjectInputStream

    (二)、ObjectOutputStream

    五、实例

    private static final String TMP_FILE = "person.tmp";  
    public static void main(String[] args) {   
      write();
      read();
    }
    // ObjectOutputStream 
    private static void write() { 
      ObjectOutputStream oos = null;
      try {
        oos = new ObjectOutputStream(new FileOutputStream(TMP_FILE));
        oos.writeBoolean(true);
        oos.writeByte((byte)65);
        oos.writeChar('a');
        oos.writeInt(20131015);
        oos.writeFloat(3.14F);
        oos.writeDouble(1.414D);
        // 写入HashMap对象
        HashMap map = new HashMap();
        for (int i = 0; i < 3; i++) {
          map.put("demo"+i, i);
        }
        oos.writeObject(map);
        Person person = new Person("xiaoming", 20);
        oos.writeObject(person);
      } catch (Exception ex) {
        ex.printStackTrace();
      }finally {
        try {
          if(oos != null) {
            oos.close();
          }    
        }catch(Exception e) {
          e.printStackTrace();
        }
      }
    }
    
    // ObjectInputStream
    private static void read() {
      ObjectInputStream ois = null;
      try {
        ois = new ObjectInputStream(new FileInputStream(TMP_FILE));
        System.out.println("boolean : " + ois.readBoolean());
        System.out.println("byte : " + (ois.readByte()&0xff));
        System.out.println("char : " + ois.readChar());
        System.out.println("int : " + ois.readInt());
        System.out.println("float : " + ois.readFloat());
        System.out.println("double : " + ois.readDouble());
        // 读取HashMap对象
        HashMap map = (HashMap) ois.readObject();
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
          Map.Entry entry = (Map.Entry)iter.next();
          System.out.println(entry.getKey() +"--" + entry.getValue());
        }
        Person person = (Person) ois.readObject();
        System.out.println("person: " + person);
      } catch (Exception e) {
        e.printStackTrace();
      }finally {
        try {
          if(ois != null) {
            ois.close();
          }    
        }catch(Exception e) {
          e.printStackTrace();
        }
      }
    }
  • 相关阅读:
    coredump文件设置及调试
    github上传本地代码库步骤
    ubuntu上SVN版本升级到1.7
    ubuntu 上samba创建共享组目录
    linux下创建只有某个用户组可用的文件夹
    usermod -a表示在原来所属组的基础上追加
    linux mount
    Ubuntu Bash and Dash
    svn co 默认密钥' GNOME keyring
    精简版ffmpeg编译脚本
  • 原文地址:https://www.cnblogs.com/lingq/p/12918735.html
Copyright © 2020-2023  润新知