ステップアップ--javaベース(21)--シーケンス化の簡単な例
6814 ワード
この記事は以下のとおりです.http://blog.163.com/benbenfafa_88/blog/static/649301622015237158142/オリジナルを尊重
簡単に言えばシーケンス化はオブジェクトストリームを処理するためのメカニズムであり、オブジェクトストリームとはオブジェクトの内容をストリーミングすることであり、ストリームの概念はここでは言うまでもなく(I/Oである)、ストリーミング後のオブジェクトに対して読み書き操作を行うこともできるし、ストリーミング後のオブジェクトをネットワーク間に転送することもできる(注:オブジェクトをネットワークに転送するにはストリーミングを行う必要がある)!オブジェクトストリームの読み書き操作で問題が発生しますが、シーケンス化メカニズムはこれらの問題を解決するために使用されます.
質問の引き出し:上記のように、読み書き対象にはどのような問題があるのでしょうか.たとえば、オブジェクトをディスクファイルに書き込んでから読み込むと何か問題がありますか?焦らないでください.最大の問題はオブジェクト参照です.たとえば、AとBの2つのクラスがある場合、BクラスにはAクラスのオブジェクトへの参照が含まれています.次に、2つのクラスをインスタンス化します{A a=new A();B b=new B()}.このとき、メモリに実際に2つのスペースが割り当てられ、1つのストレージオブジェクトa、1つのストレージオブジェクトbが割り当てられます.次に、ディスクの1つのファイルに書き込みたいと思います.ファイルに書き込み中に問題が発生しました!オブジェクトbにはオブジェクトaへの参照が含まれているため、システムは自動的にaのデータをbにコピーします.そうすると、ファイルからオブジェクトを復元するとき(つまりメモリに再ロードするとき)にメモリに3つの空間が割り当てられ、オブジェクトaは同時にメモリに2つ保存されます.結果を考えてみましょう.オブジェクトaのデータを変更したい場合は、それは、オブジェクトデータの一貫性を達成するためにコピーを検索する必要はありません.これは私たちが望んでいるものではありません.
次のシーケンス化メカニズムの解決策:1.ディスクに保存されているすべてのオブジェクトにシリアル番号(1,2,3など)を取得します.2.オブジェクトを保存する場合は、オブジェクトが保存されているかどうかを確認します.3.以前に保存した場合は、「既に保存されているシリアル番号xを持つオブジェクトと同じ」というタグを書き込むだけで、そうでない場合は、そのオブジェクトを保存します.
以上の手順でシーケンス化メカニズムによりオブジェクト参照の問題を解決しました!
シーケンス化の実装にはシーケンス化可能なクラス実装Serializableインタフェースが必要になります.このインタフェースは実装する必要のない方法です.implements Serializableは、オブジェクトがシーケンス化可能であることを示すためだけに、出力ストリーム(FileOutputStreamなど)を使用してObjectOutputStream(オブジェクトストリーム)オブジェクトを構築し、次にObjectOutputStreamオブジェクトのwriteObjectを使用します.(Object obj)メソッドでは、パラメータがobjのオブジェクトを書き出し(すなわち、その状態を保存)、復元するには入力ストリームを使用します.
シーケンス化の過程で、一部のデータフィールドはシーケンス化したくない.このようなフィールドについては、定義時にtransientキーワードを付けるだけでよい.transientフィールドシーケンス化メカニズムではスキップされてファイルに書き込まれず、もちろん復元できない.ただし、あるフィールドをシーケンス化したい場合があるが、SDKでの定義はシーケンス化できないシーケンス化メカニズムは、このような特殊な問題を含むクラスに次のような方法で定義されています.
(注:これらのメソッドは、呼び出しを表示する必要がないため、シーケンス化メカニズムが自動的に呼び出されるため、定義はプライベートでなければなりません)以上の方法では、シーケンス化したいデータフィールドやシーケンス化できないデータフィールドを手動で書き出したり読み込んだりすることができます.
次の例では、java.awt.geomパッケージのPoint 2 D.Doubleクラスはシーケンス化できません.このクラスはSerializableインタフェースを実装していないため、私の例ではLabeledPointクラスのデータフィールドとして使用し、シーケンス化方法を示します.
簡単に言えばシーケンス化はオブジェクトストリームを処理するためのメカニズムであり、オブジェクトストリームとはオブジェクトの内容をストリーミングすることであり、ストリームの概念はここでは言うまでもなく(I/Oである)、ストリーミング後のオブジェクトに対して読み書き操作を行うこともできるし、ストリーミング後のオブジェクトをネットワーク間に転送することもできる(注:オブジェクトをネットワークに転送するにはストリーミングを行う必要がある)!オブジェクトストリームの読み書き操作で問題が発生しますが、シーケンス化メカニズムはこれらの問題を解決するために使用されます.
質問の引き出し:上記のように、読み書き対象にはどのような問題があるのでしょうか.たとえば、オブジェクトをディスクファイルに書き込んでから読み込むと何か問題がありますか?焦らないでください.最大の問題はオブジェクト参照です.たとえば、AとBの2つのクラスがある場合、BクラスにはAクラスのオブジェクトへの参照が含まれています.次に、2つのクラスをインスタンス化します{A a=new A();B b=new B()}.このとき、メモリに実際に2つのスペースが割り当てられ、1つのストレージオブジェクトa、1つのストレージオブジェクトbが割り当てられます.次に、ディスクの1つのファイルに書き込みたいと思います.ファイルに書き込み中に問題が発生しました!オブジェクトbにはオブジェクトaへの参照が含まれているため、システムは自動的にaのデータをbにコピーします.そうすると、ファイルからオブジェクトを復元するとき(つまりメモリに再ロードするとき)にメモリに3つの空間が割り当てられ、オブジェクトaは同時にメモリに2つ保存されます.結果を考えてみましょう.オブジェクトaのデータを変更したい場合は、それは、オブジェクトデータの一貫性を達成するためにコピーを検索する必要はありません.これは私たちが望んでいるものではありません.
次のシーケンス化メカニズムの解決策:1.ディスクに保存されているすべてのオブジェクトにシリアル番号(1,2,3など)を取得します.2.オブジェクトを保存する場合は、オブジェクトが保存されているかどうかを確認します.3.以前に保存した場合は、「既に保存されているシリアル番号xを持つオブジェクトと同じ」というタグを書き込むだけで、そうでない場合は、そのオブジェクトを保存します.
以上の手順でシーケンス化メカニズムによりオブジェクト参照の問題を解決しました!
シーケンス化の実装にはシーケンス化可能なクラス実装Serializableインタフェースが必要になります.このインタフェースは実装する必要のない方法です.implements Serializableは、オブジェクトがシーケンス化可能であることを示すためだけに、出力ストリーム(FileOutputStreamなど)を使用してObjectOutputStream(オブジェクトストリーム)オブジェクトを構築し、次にObjectOutputStreamオブジェクトのwriteObjectを使用します.(Object obj)メソッドでは、パラメータがobjのオブジェクトを書き出し(すなわち、その状態を保存)、復元するには入力ストリームを使用します.
シーケンス化の過程で、一部のデータフィールドはシーケンス化したくない.このようなフィールドについては、定義時にtransientキーワードを付けるだけでよい.transientフィールドシーケンス化メカニズムではスキップされてファイルに書き込まれず、もちろん復元できない.ただし、あるフィールドをシーケンス化したい場合があるが、SDKでの定義はシーケンス化できないシーケンス化メカニズムは、このような特殊な問題を含むクラスに次のような方法で定義されています.
private void readObject(ObjectInputStream in) throws
IOException, ClassNotFoundException;
private void writeObject(ObjectOutputStream out) throws IOException;
(注:これらのメソッドは、呼び出しを表示する必要がないため、シーケンス化メカニズムが自動的に呼び出されるため、定義はプライベートでなければなりません)以上の方法では、シーケンス化したいデータフィールドやシーケンス化できないデータフィールドを手動で書き出したり読み込んだりすることができます.
次の例では、java.awt.geomパッケージのPoint 2 D.Doubleクラスはシーケンス化できません.このクラスはSerializableインタフェースを実装していないため、私の例ではLabeledPointクラスのデータフィールドとして使用し、シーケンス化方法を示します.
import java.io.*;
import java.awt.geom.*;
public class TransientTest
{
public static void main(String[] args)
{
LabeledPoint label = new LabeledPoint("Book", 5.00, 5.00);
try
{
System.out.println(label);//
ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("Label.txt"));
out.writeObject(label);
out.close();
System.out.println(label);//
ObjectInputStream in = new ObjectInputStream(new
FileInputStream("Label.txt"));
LabeledPoint label1 = (LabeledPoint) in.readObject();
in.close();
System.out.println(label1);// 1.0
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class LabeledPoint implements Serializable
{
public LabeledPoint(String str, double x, double y)
{
label = str;
point = new Point2D.Double(x, y);
}
private void writeObject(ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
out.writeDouble(point.getX());
out.writeDouble(point.getY());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
double x = in.readDouble() + 1.0;
double y = in.readDouble() + 1.0;
point = new Point2D.Double(x, y);
}
public String toString()
{
return getClass().getName()+ "[label = " + label+ ", point.getX() = " + point.getX()+ ", point.getY() = " + point.getY()+ "]";
}
private String label;
transient private Point2D.Double point;
}