この記事では、シリアル化とは何か、および Java でシリアル化がどのように機能するかを説明します。
図 1. スレッドのグラフィック表示
ストリームは主に次の 2 種類に分類されます。
導入
オブジェクトのシリアル化とは、出力ストリーム (たとえば、外部ファイル) を使用して、オブジェクト自体と参照する他のオブジェクトの完全なコピーを保存するオブジェクトの機能です。こうすることで、必要なときに少し後でシリアル化された (保存された) コピーからオブジェクトを再作成できます。JDK 1.1 で導入された新機能であるオブジェクトのシリアル化は、グループまたは個々のオブジェクトをビットストリームまたはバイト配列に変換して、ネットワーク上で保存または送信する機能を提供します。また、前述したように、特定のビット ストリームまたはバイト配列を Java オブジェクトに変換して戻すことができます。ObjectInputStream
これは主にとクラスのおかげで自動的に行われますObjectOutputStream
。Serializable
プログラマは、クラスの作成時にインターフェイスを実装することによって、この機能を実装することを決定できます。シリアル化のプロセスはオブジェクトマーシャリングとも呼ばれ、逆シリアル化はアンマーシャリングとも呼ばれます。シリアル化は、オブジェクトがそれ自体のコピーと、そのオブジェクトによって参照される他のすべてのオブジェクトを、.html ファイルを使用して外部ファイルに保存できるようにするメカニズムですObjectOutputStream
。JFrame
保存されるオブジェクトは、タイプに関係なく、データ構造、ダイアグラム、クラス オブジェクト、またはその他のオブジェクトです。同時に、シリアル化ではオブジェクトの型に関する情報が保存されるため、後で逆シリアル化されるときに、その情報を使用してオブジェクトの正確な型が再作成されます。したがって、シリアル化は次の機能を提供します。
- オブジェクトを保存するためのシステム。つまり、オブジェクトのプロパティを外部ファイル、ディスク、またはデータベースに保存します。
- リモートプロシージャコールシステム。
- たとえば、COM、COBRA などのソフトウェア コンポーネントにおけるオブジェクト配布システム。
- 時間の経過に伴う変数データの変化を識別するシステム。
ストリーム:
すべてのプログラムは、そのデータを記憶場所またはパイプに書き込む必要があり、すべてのプログラムはパイプまたは記憶場所からデータを読み取る必要があります。Java では、プログラムがデータを書き込む、またはプログラムがデータを読み取るチャネルをStreams(Stream
)と呼びます。
- *Streams と呼ばれるバイト ストリーム クラス
- *Reader および *Writer という文字ストリーム クラス
持続性
オブジェクトの永続性とは、オブジェクトが存続する能力、言い換えれば、プログラムの実行中に「生き残る」能力です。これは、実行時に作成されたオブジェクトは、そのオブジェクトが使用されなくなると必ず JVM スカベンジャーによって破棄されることを意味します。しかし、永続化 API が実装されている場合、これらのオブジェクトは JVM スカベンジャーによって破壊されず、代わりに「生存」が許可されるため、次回アプリケーションが起動されたときにもアクセスできるようになります。言い換えれば、永続性とは、実行中のアプリケーションの存続期間とは関係なく、オブジェクトの存続期間が存在することを意味します。永続性を実装する 1 つの方法は、オブジェクトを外部ファイルまたはデータベースのどこかに保存し、後でそれらのファイルまたはデータベースをソースとして使用して復元することです。ここでシリアル化が登場します。非永続オブジェクトは、JVM が実行されている限り存在します。シリアル化されたオブジェクトは、ストリームに変換された単純なオブジェクトであり、その後、保存および回復のために外部ファイルに保存されるか、ネットワーク経由で転送されます。シリアル化可能なインターフェイスの実装
java.io.Serializable
どのクラスも、そのクラスのオブジェクトをシリアル化するためのインターフェイスを実装する必要があります。インターフェイスにSerializable
はメソッドはなく、シリアル化可能として識別できるようにクラスにマークを付けるだけです。シリアル化されたクラス オブジェクトのフィールドのみを保存できます。メソッドまたはコンストラクターは、シリアル化されたストリームの一部として保存されません。オブジェクトが別のオブジェクトへの参照として機能する場合、そのオブジェクトのクラスがインターフェースを実装していれば、そのオブジェクトのフィールドもシリアル化されますSerializable
。言い換えれば、このようにして取得されたこのオブジェクトのグラフは完全にシリアル化可能です。オブジェクト グラフには、オブジェクトとそのサブオブジェクトのフィールドのツリーまたは構造が含まれます。インターフェイスの実装に役立つ 2 つの主要なクラスSeriliazable
:
ObjectInputStream
ObjectOutputStream
import java.io.*;
public class RandomClass implements Serializable {
// Генерация рандомного значения
private static int r() {
return (int)(Math.random() * 10);
}
private int data[];
// Конструктор
public RandomClass() {
datafile = new int[r()];
for (int i=0; i<datafile.length; i++)
datafile[i]=r();
}
public void printout() {
System.out.println("This RandomClass has "+datafile.length+" random integers");
for (int i=0; i<datafile.length; i++) {
System.out.print(datafile[i]+":");
System.out.println();
}
}
上記のコードでは、シリアル化可能なクラスが作成されます。シリアル化インターフェイスによって「マーク」されます。このクラスは、インスタンスの作成時にランダムな整数の配列を作成します。以下のコードは、 を使用してオブジェクトをストリームに書き込む機能を示していますObjectOutputStream
。プログラムには整数の配列がありますが、シリアル化のために内部オブジェクトを反復する必要はありません。インターフェースはSeriliazable
これを自動的に処理します。 リスト 2. ファイルに出力するためにオブジェクトをシリアル化する簡単な例
import java.io.*;
import java.util.*;
public class OutSerialize {
public static void main (String args[]) throws IOException {
RandomClass rc1 = new RandomClass();
RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода an object в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
out.writeObject(now);
out.writeObject(rc1);
out.writeObject(rc2);
out.close();
System.out.println("I have written:");
System.out.println("A Date object: "+now);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
ObjectInputStream
以下のコードは、外部ファイルからシリアル化されたデータをプログラムに読み取る クラスの機能を示しています。オブジェクトは、ファイルに書き込まれたのと同じ順序で読み取られることに注意してください。 リスト 3. シリアル化されたオブジェクトの読み取りまたは逆シリアル化
import java.io.*;
import java.util.*;
public class InSerialize {
public static void main (String args[]) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream (new FileInputStream("objects.dat"));
Date d1 = (Date)in.readObject();
RandomClass rc1 = (RandomClass)in.readObject();
RandomClass rc2 = (RandomClass)in.readObject();
System.out.println("I have read:");
System.out.println("A Date object: "+d1);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
AWT クラスを含め、ほとんどすべての Java クラスをシリアル化できます。ウィンドウであるフレームには、一連のグラフィック コンポーネントが含まれています。フレームがシリアル化されている場合、シリアル化エンジンがこれを処理し、そのすべてのコンポーネントとデータ (位置、コンテンツなど) をシリアル化します。一部の Java クラス オブジェクトは、一時的なオペレーティング システム リソースを参照するデータが含まれているため、シリアル化できません。たとえば、クラスjava.io.FileInputStream
とjava.lang.Thread
。オブジェクトにシリアル化不可能な要素への参照が含まれている場合、シリアル化操作全体が失敗し、例外がスローされますNotSerializableException
。オブジェクトがシリアル化されていないオブジェクトの参照を参照している場合、そのオブジェクトはtransientキーワードを使用してシリアル化できます。 リスト 4. transientキーワードを使用したシリアル化可能オブジェクトの作成
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
private String studentID;
private int sum;
}
シリアル化におけるセキュリティ
Java でクラスをシリアル化するには、そのすべてのデータをストリーム経由で外部ファイルまたはデータベースに渡す必要があります。必要に応じていつでもシリアル化するデータを制限できます。これを行うには 2 つの方法があります。- 一時的として宣言された各クラス パラメーターはシリアル化されません (デフォルトでは、すべてのクラス パラメーターはシリアル化されます)。
- または、シリアル化するクラスの各パラメーターはタグでマークされます
Externalizable
(デフォルトでは、パラメーターはシリアル化されません)。
ObjectOutputStream
マークされている場合、オブジェクトで呼び出されたとき、データ フィールドは でシリアル化されません。例えば:。一方、オブジェクトのデータをシリアル化可能として明示的に宣言するには、そのオブジェクトのデータの書き込みと読み取りを明示的に行うクラスとしてマークを付ける必要があります。 private transient String password
ExternalizablewriteExternal
readExteranl
結論
オブジェクトのシリアル化の機能は、データを転送する方法として多くの分散システムで使用されています。しかし、シリアル化によって隠された詳細が明らかになるため、抽象データ型の信頼性が破壊され、ひいてはカプセル化も破壊されます。同時に、シリアル化されたオブジェクトのデータが、元の元のオブジェクトにあったデータと同じであることを知っておくと便利です。これは、複数行のコードが使用されている場合でも、インターフェイスを実装してObjectInputValidation
メソッドをオーバーライドする絶好の機会でもあります。validateObject()
オブジェクトが見つからない場合は、適切に例外をスローできますInvalidObjectException
。元の記事: Java でのシリアル化の仕組み
GO TO FULL VERSION