ホームページ  >  記事  >  Java  >  JAVAシリアル化

JAVAシリアル化

黄舟
黄舟オリジナル
2017-02-24 09:44:301526ブラウズ

1. 質問:

オブジェクトをファイルに書き込みたいが、バイト ストリームでも文字ストリームでも要件を満たせない場合、オブジェクトをファイルに書き込むにはどうすればよいですか?
バイト文字ストリームを使用する場合、オブジェクトをバイト/文字に変換してからファイルに書き込む必要があります。ただし、バイト文字ストリームにはオブジェクトをバイトに変換する方法がありません。

2. シリアル化と逆シリアル化

Java シリアル化: オブジェクトをバイトに変換するプロセス。これはまさに私のニーズを満たします。
Java 逆シリアル化: バイトをオブジェクトに復元するプロセス
これは、オブジェクトをファイルに書き込み、オブジェクトを読み取るという要求を満たします

3. シリアル化と逆シリアル化の使用シナリオ

  • a. オブジェクトをハードディスクに書き込みます。

    b、ネットワーク間の送信

  • テキスト、オーディオ、ビデオなどがネットワーク上で送信される場合、ネットワーク上でオブジェクトを送信したい場合は、シリアル化とを使用する必要があります。逆シリアル化はデータの送受信を満たします。
      ###4. シリアル化と逆シリアル化の利点
    • まず、シリアル化を通じてデータの永続性を実現し、データをローカル ハードディスクに永続的に保存します。

      次に、リモート ネットワーク通信を実現し、シリアル化を使用して一連のバイトを作成します。オブジェクトはネットワーク経由で送信できます。


    • 5. シリアル化と逆シリアル化の実装方法
5.1.

Serializable インターフェイスを実装する

Serializable インターフェイスにはメソッドがありませんが、このクラスがシリアル化できることを Java メカニズムに伝えるための識別子のみを提供します。 ; この識別子が作成されていない場合、SerialVersionUID は

クラス名、インターフェース名、メンバーのメソッドと属性

などに基づいて
64ビットのハッシュフィールドを生成します。

SerialVersionUID がない場合、通常、シリアル化後にクラスの属性が変更されると、逆シリアル化中にエラーが報告されます。疲れた属性が変更されているため、Java メカニズムは、 SerialVersionUID が元の ID と一致しないため、逆シリアル化が失敗しました。

  • SerialVersionUID の実装が設定されている場合、属性またはメソッドが追加された場合でも、シリアル化と逆シリアル化を実行できます。
  • 新しく追加された属性値のみが null であるか、そうでないように見えます。属性の値が削除されます。
    • package com.chb.test;import java.io.Serializable;public class Student implements Serializable{
          //序列化标识
          private static final long serialVersionUID = 1L;    
          private String name;    
          private int age;    
          private String sex;    
          public Student() {
          }    
          public Student(String name, int age, String sex) {        
          super();        
          this.name = name;        
          this.age = age;        
          this.sex = sex;
          }    
          @Override
          public String toString() {        
          return "Student{"
                      +"姓名:"+this.name
                      +"性别:"+this.sex
                      +"年龄"+this.age
                      + "}";
          }    
          /**setter getter 省略。。。*/    
          }

      5.2、ObjectOutputStream と ObjectInputStream
    Serializalable インターフェイスは表現のみを提供し、オブジェクトをバイナリ シーケンスに変換し、バイナリ シーケンスをオブジェクトに復元するのは、ObjectOutputStream と OjbectInputStream によって提供される 2 つのメソッド、writeObject() と readObject() です。

writeObject()

  • public static void write(Student s1) throws Exception {
            FileOutputStream fos = new FileOutputStream(filename);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s1);
            oos.close();
    }

  • readObject()
  • public static Student read() throws Exception {
            FileInputStream fis = new FileInputStream(filename);
            ObjectInputStream ois = new ObjectInputStream(fis);
            Student stu = new Student();        //使用readeObject()进行反序列化
            stu= (Student) ois.readObject();
            ois.close();        return stu;
    }

    6. 場合によっては、一部の機密フィールドやクラスの参照型をシリアル化すべきではありません。メンバーはシリアル化できません。このため、

    transient
  • を使用してこれらのメンバーを変更し、シリアル化されないようにする必要があります。例: 銀行口座オブジェクト、口座金額をシリアル化したくない場合。
上記の Student クラスを変更し、transient

transient private String sex;

を使用して sex 属性を変更し、それをシリアル化

Student s1 = new Student("roase",19, "女");
write(s1);
deserialize して、読み取りオブジェクトが見つかりました: sex が null であり、transient によって変更された属性がシリアル化されないことを示します。

6.1defaultWriteObjectとdefaultReadObject()

上記の一時的なメンバーの年齢について、ここでシリアル化可能および逆シリアル化したい場合、何をすべきか:
JAVAシリアル化

1.一時的な変更を削除します

    2. 2 つのメソッドを提供します
  •     private void writeObject(ObjectOutputStream out) throws Exception{        
        out.defaultWriteObject();        
        out.writeInt(age);
        }    
        private void  readObject(ObjectInputStream in) throws Exception {        
        in.defaultReadObject();
            age=in.readInt();
        }
  • writeObject() メソッドでは、ObjectOutputStream のdefaultWriteObject() メソッドが最初に呼び出され、このメソッドは
  • デフォルトのシリアル化メカニズム

    を実行し、この時点では age は無視されます。次に、writeInt() メソッドを呼び出して、age フィールドを ObjectOutputStream に明示的に書き込みます。 readObject() の機能はオブジェクトを読み取ることであり、その原理は writeObject() メソッドと同じです。 read() アプリケーションを再度実行すると、次の出力が得られます:

1. 問題:

オブジェクトをファイルに書き込みたい場合、バイト ストリームでも文字ストリームでも書き込みできないことがわかります。要件を満たします。

オブジェクトをファイルに書き込むには? JAVAシリアル化

バイト文字ストリームを使用する場合、オブジェクトをバイト/文字に変換してからファイルに書き込む必要があります。ただし、バイト文字ストリームにはオブジェクトをバイトに変換する方法がありません。

2、序列化与反序列化

Java序列化:将对象转为字节的过程,这正好符合我的需求。
Java反序列化:将字节恢复为对象的过程
这满足我们想文件中写对象,和读取对象

3、序列化和反序列化的使用场景

  • a、将对象写道硬盘中;

  • b、网络间传输

    • 当在网络上传送文本,音频,视频等,都是转化为二进制序列传送,我们要在网络上传送对象,就必须使用序列化和反序列化,满足数据的发送和接收。
      ###4、序列化和反序列化的好处
      一、实现数据的持久化,通过序列化将数据永久的保存在本地的硬盘上;
      二、实现远程网络通信,利用序列化,使得在网络上可以传输对象的字节序列。

5、如何实现序列化和反序列化

5.1 、实现Serializable接口

  Serializable接口没有任何方法,只是提供一个标识 , 用来告诉java机制该类可以被序列化;
     如果没有创建这个标识,java机制将会自动的创建一个,SerialVersionUID是根据类名, 接口名,成员方法及属性等来生成一个64位哈希字段

  • 如果没有SerialVersionUID, 通常我们会发现,如果在序列化后,修改了类的属性, 在进行反序化,会报错,因为累的属性修改了,java机制会重新创建一个SerialVersionUID, 导致与原来的ID不一致, 反序列化失败。

    • 如果设置了实现SerialVersionUID, 保证版本的兼容性, 即使添加了属性或方法, 仍然能进行序列化和反序列化, 只是新添加的属性值为null,或不显示被删除属性的值。

package com.chb.test;import java.io.Serializable;public class Student implements Serializable{
    //序列化标识
    private static final long serialVersionUID = 1L;    
    private String name;    
    private int age;    
    private String sex;    
    public Student() {
    }    
    public Student(String name, int age, String sex) {        
    super();        
    this.name = name;        
    this.age = age;        
    this.sex = sex;
    }    
    @Override
    public String toString() {        
    return "Student{"
                +"姓名:"+this.name
                +"性别:"+this.sex
                +"年龄"+this.age
                + "}";
    }    
    /**setter getter 省略。。。*/    }

5.2、ObjectOutputStream与ObjectInputStream

  Serializalable接口只是提供一个表示,将对象转为二进制序列,和二进制序列恢复成对象是由ObjectOutputStream和OjbectInputStream提供的两个方法:writeObject()和readObject()

  • writeObject()

public static void write(Student s1) throws Exception {
        FileOutputStream fos = new FileOutputStream(filename);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(s1);
        oos.close();
}
  • readObject()

public static Student read() throws Exception {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        Student stu = new Student();        //使用readeObject()进行反序列化
        stu= (Student) ois.readObject();
        ois.close();        return stu;
}

6、transient

在某种场合,我们对某些敏感字段不要进行序列化,或者类的引用类型的成员不能够进行序列化, 这是我们需要使用transient来修饰这些成员, 以避免它们被序列化。如:银行账户对象,不希望对账户金额进行序列化。
修改上面的Student类,将sex属性使用transient修饰

transient private String sex;

再进行序列化

Student s1 = new Student("roase",19, "女");
write(s1);

反序列化, 读取的对象发现:sex为null,说明被transient修饰的属性不会被序列化。
JAVAシリアル化

6.1 defaultWriteObject和defaultReadObject()

对于上面的被transient的成员age, 如果我们想让它能够在此序列化和反序列化,要如何做:

  • 1、去掉transient的修饰

  • 2、提供两个方法

    private void writeObject(ObjectOutputStream out) throws Exception{        
    out.defaultWriteObject();        
    out.writeInt(age);
    }    
    private void  readObject(ObjectInputStream in) throws Exception {        
    in.defaultReadObject();
        age=in.readInt();
    }

在writeObject()方法中会先调用ObjectOutputStream中的defaultWriteObject()方法,该方法会执行默认的序列化机制,此时会忽略掉age字段。然后再调用writeInt()方法显示地将age字段写入到ObjectOutputStream中。readObject()的作用则是针对对象的读取,其原理与writeObject()方法相同。再次执行read()应用程序,则又会有如下输出:

JAVAシリアル化

 以上就是JAVA之序列化的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。