シリアル化
Javaは、オブジェクトのシリアル化のメカニズムを提供します。このメカニズムでは、オブジェクトをバイトシーケンスとして表すことができます。バイトシーケンスには、オブジェクトのデータ、オブジェクトのタイプに関する情報、およびオブジェクトに格納されているデータが含まれます。タイプの。
シリアル化されたストレージデータの利点
シリアル化されたファイルを使用すると、プログラムを元の状態に簡単に復元できます。シリアル化されたファイルは、元のコンテンツではなくエンコードされているため、より安全です。シリアル化されたオブジェクトは、JVM間で転送するのに便利です。これらのJVMは、同じコンピューター上またはリモートに配置できます。
シリアル化を使用する場合
オブジェクトをオンラインで送信するか、ディスクに保存して、将来のある時点でアクセスできるようにする必要がある場合は、この場合、オブジェクトをシリアル化できます。オブジェクトの内部状態がセカンダリストレージデバイス(ハードディスク)への出力やネットワーク経由の送信に適していない場合は、シリアル化の使用に注意する必要があります。オブジェクトのシリアル化は、Javaリモートメソッド呼び出しとJavaBeanの2つの機能をサポートするために使用されます。
Javaでのシリアル化の実装
Javaでシリアル化と逆シリアル化を実装するクラスは、それぞれObjectOutputStreamとObjectInputStreamです。
ObjectOutputStreamシリアル化メソッド:
public final void writeObject(Object x) throws IOException
ObjectInputStream逆シリアル化メソッド:
public final Object readObject() throws IOException,ClassNotFoundException
このメソッドは、ストリームから次のオブジェクトを取得し、オブジェクトを逆シリアル化します。その戻り値はObjectであるため、適切なデータ型に変換する必要があります。
コード例:
従業員クラス
package JavaReview.FileIO;
import java.io.Serializable;
public class Employee implements Serializable {
public String name;
public String address;
public transient int SSN;
public int number;
public Task ta;
public Employee(String name, String address, int SSN, int number, Task ta) {
this.name = name;
this.address = address;
this.SSN = SSN;
this.number = number;
this.ta = new Task(ta);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", SSN=" + SSN +
", number=" + number +
", ta=" + ta.toString() +
'}';
}
}
class Task implements Serializable{
public String taskName;
public String taskContent;
public Task(Task ta) {
this.taskName = ta.taskName;
this.taskContent = ta.taskContent;
}
public Task(String taskName,String taskContent ){
this.taskContent=taskContent;
this.taskName=taskName;
}
@Override
public String toString() {
return "Task{" +
"taskName='" + taskName + '\'' +
", taskContent='" + taskContent + '\'' +
'}';
}
}
シリアル化と逆シリアル化を実現する
package JavaReview.FileIO;
import java.io.*;
public class SerializeDemo {
public static void main(String[] args) {
Task ta=new Task("项目XXX","完成XXX");
Employee ee=new Employee("张三","中国北京市",12312,111,ta);
Employee ee2=new Employee("李四","中国上海市",122222,222,ta);
try {
//开始序列化对象ee,ee2
FileOutputStream outfileStream=new FileOutputStream("example.ser");
ObjectOutputStream os=new ObjectOutputStream(outfileStream);
os.writeObject(ee);
os.writeObject(ee2);
os.close();
outfileStream.close();
System.out.println("写入文件成功");
//开始反序列化对象ee,ee2
FileInputStream infileStream=new FileInputStream("example.ser");
ObjectInputStream is=new ObjectInputStream(infileStream);
Employee e=null;
Employee e2=null;
e=(Employee) is.readObject();
e2=(Employee) is.readObject();
System.out.println(e.toString());
System.out.println(e2.toString());
infileStream.close();
is.close();
}catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
運転結果
写入文件成功
Employee{name='张三', address='中国北京市', SSN=0, number=111, ta=Task{taskName='项目XXX', taskContent='完成XXX'}}
Employee{name='李四', address='中国上海市', SSN=0, number=222, ta=Task{taskName='项目XXX', taskContent='完成XXX'}}
クラスのオブジェクトを正常にシリアル化するには、次の2つの条件を満たす必要があります。
- このクラスは、java.io.Serializableオブジェクトを実装する必要があります。Serializableはインターフェイスであり、実装するメソッドはありません。その唯一の機能は、それを実装するクラスをシリアル化できることを宣言することです。
- このクラスのすべての属性はシリアル化可能である必要があります。シリアル化できない属性がある場合、その属性は、transientキーワードを使用してtransientとしてマークする必要があります。
上記の例では、オブジェクトがシリアル化されている場合、属性SSNの値は111222333ですが、属性が短いため、値は出力ストリームに送信されません。したがって、逆シリアル化後のEmployeeオブジェクトのSSN属性は0です。同時に、シリアル化されたオブジェクトにはオブジェクト参照taがあり、クラスtaもSerializableインターフェイスを継承しているため、ta変数自体とtaが指すオブジェクトのコンテンツはシリアル化できます。Taskのインターフェース継承を削除すると、インターフェースを継承しないというエラーが報告されます。次のように:
java.io.NotSerializableException: JavaReview.FileIO.Task
以下に、いくつかのポイントを具体的に説明します。
-
シリアル化と逆シリアル化の両方を、操作のためにtry / catchに入れる必要があります。デシリアライズでは、読み取ったファイルが存在しない場合を考慮する必要があるため、ClassNotFoundException例外を追加する必要があります。
-
FileOutputStream / FileInputStreamはバイトをファイルに書き込んだり読み取ったりできますが、通常はバイトを直接書き込むのではなく、オブジェクトレベルの観点から書き込みます。したがって、高レベルの接続ストリームが必要です。クラスObjectInputStream
とObjectOutputStreamは高いです。。階層データフローは、オブジェクトをバイトストリームに変換できます。 -
一部の変数はシリアル化できません。たとえば、このデータは動的です。つまり、実行中にのみ検出され、保存する必要がないか、保存する必要がありません。意味のある実行中にその場で作成できます。プログラムが閉じられると、接続自体は次のようになります。使用するだけでなく、次回実行時に再作成する必要があります。
-
オブジェクトの継承ツリーにシリアル化できない祖先クラスがある場合、シリアル化できないクラスとその上のクラス(シリアル化できる場合でも)のコンストラクターが実行されます。コンストラクターチェーンが開始されると、停止することはできません。つまり、シリアル化できない最初の親クラスから開始すると、すべてが再初期化されます。
-
一時変数にはnullオブジェクト参照が割り当てられるか、プリミティブプライマリデータ型のデフォルトは0、falseなどになります。
-
デシリアライズする場合、新しいオブジェクトはヒープ上に構成されますが、コンストラクターは実行されません。保存時の状態に戻るため、コンストラクターを実行すると完全に新しい状態になります。
-
staticはオブジェクト変数ではなくクラス変数であるため、静的変数はシリアル化されません。つまり、オブジェクトのストレージはその値に影響を与えません。
-
デシリアライズする場合、オブジェクトの読み取り順序は書き込み順序と同じです。
-
オブジェクトのシリアル化の制限の1つは、Javaソリューションしか解決できず、Javaプログラムのみがこのオブジェクトを逆シリアル化できることです。より相互運用可能なソリューションは、データをXML形式に変換して、さまざまなプラットフォームや言語で使用できるようにすることです。
シリアル化の最適化
多数の特定のクラスオブジェクトの読み取りと書き込みが必要な場合は、Eインターフェイスの使用を検討する必要があります。
Externalizableインスタンスクラスの唯一の機能は、シリアル化ストリームに書き込むことができることです。このクラスは、インスタンスコンテンツの保存と復元を担当します。オブジェクトとそのスーパータイプのストリーム形式とコンテンツを完全に制御したい場合は、ExternalizableインターフェースのwriteExternalメソッドとreadExternalメソッドを実装する必要があります。これらのメソッドは、その状態を保存するためにスーパータイプと明示的に調整する必要があります。これらのメソッドは、カスタムのwriteObjectメソッドとreadObjectメソッドを置き換えます。
シリアル化オブジェクトは、SerializableおよびExternalizableインターフェースを使用します。オブジェクト永続化メカニズムもそれらを使用できます。保存するすべてのオブジェクトは、Externalizableインターフェースをサポートしているかどうかをテストする必要があります。オブジェクトがExternalizableをサポートしている場合は、writeExternalメソッドを呼び出します。オブジェクトがExternalizableをサポートしていないが、Serializableを実装している場合は、ObjectOutputStreamを使用してオブジェクトを保存します。
外部化可能なインターフェースを使用するための要件:
- このインターフェースを実装する必要があります
- オブジェクトの状態を保存するには、writeExternalメソッドを実装する必要があります。また、状態を保存するには、上位クラスと明示的に連携する必要があります。
- writeExternalメソッドによって書き込まれたデータをストリームから読み取り、オブジェクトの状態に応答するには、readExternalメソッドを実装する必要があります。また、状態を保存するには、上位クラスと明示的に連携する必要があります。
参考資料:http://www.runoob.com/java/java-serialization.html
参考資料:「HeadFirstJava」