入力と出力--javaシーケンス化メカニズム
4946 ワード
オブジェクトのシーケンス化の目的は、オブジェクトをディスクに保存するか、ネットワーク内でオブジェクトを直接転送できるようにすることです.オブジェクトシーケンス化メカニズムにより、メモリ内のJavaオブジェクトをプラットフォームに関係のないバイナリストリームに変換して保存または転送できます.他のプログラムがこのバイナリストリームを取得すると,このバイナリストリームを元のJavaオブジェクトに復元することもできる.
シーケンス化は、RMI(Remote Method Invoke–リモートメソッド呼び出し)プロシージャのパラメータと戻り値の両方を実装するメカニズムであり、RMIはJavaEEの基礎である.したがって、シーケンス化メカニズムはJavaEEプラットフォームの基礎である.良い習慣を身につけるには、javabeanを書くときにSerializableインタフェースを実現しなければなりません.
オブジェクトにシーケンス化メカニズムをサポートさせる必要がある場合は、シーケンス化可能なクラスを許可し、シーケンス化可能なクラスを許可するために、次の2つのインタフェースの1つであるSerializableを実現する必要があります.Externalizable.実際の開発ではSerializableを直接実現すればいいのが普通ですが、後者はあまり使わないので、少なくとも私は使ったことがありません.
2:Externalizableプログラマーは、どのような情報を格納するかを決定し、このインタフェースを実装しなければならない2つの空の方法(1つの読み取り、1つの書き込み)、性能はやや良い.
2,プログラムがオブジェクトを系列化しようとすると,まずそのオブジェクトがシーケンス化されているかどうかをチェックする.
3、オブジェクトがシーケンス化されている場合、プログラムは、オブジェクトを再シーケンス化するのではなく、シーケンス化番号を直接出力します.
4,このオブジェクトがシーケンス化されていない場合、プログラムはこのオブジェクトをバイトシーケンスに変換して出力します.
では、質問が来ました.
1,もし私が2回連続してObjectOutputStreamのwriteobjectメソッドを呼び出して1つのオブジェクトをシーケンス化し、中間の過程でこのオブジェクトの属性を変更したら、この変更操作は有効になりますか? 2回目のシーケンス化は実際には発生していないため、シーケンス番号が出力されただけです.
2,逆シーケンス化で読み取ったものは何ですか.Javaオブジェクトのデータですか、Javaクラスですか. 明らかに、Javaの逆シーケンス化はJavaオブジェクトのデータを読み取るので、逆シーケンス化を採用してJavaデータを復元する場合は、Javaオブジェクトが属するクラスのclassファイルを提供しなければなりません.そうしないと、ClassNotFoundExceptionが発生します. 3,逆シーケンス化メカニズムJavaオブジェクトを復元する際に,コンストラクタを呼び出してオブジェクトを初期化する必要はない.クラスのコンストラクタがprivateであるにもかかわらず、逆シーケンス化がJavaオブジェクトを作成できる場合、この問題をどのように解決しますか?この点については、実は私も深く理解していません.1つの解決策はreadResolve()メソッドを書き換えることです.
4,逆シーケンス化Javaオブジェクトはこのオブジェクトが属するクラスのclassファイルを提供しなければならない.現在の問題はプロジェクトのアップグレードに伴い、システムのclassファイルも変化することである.Javaはどのように2つのclassファイルの互換性を保証するのか. この時バージョン番号が役に立った(private static final long serialVersionUID=1 L).バージョン番号はJavaクラスのシリアル番号バージョンを示すために使用され、クラスがアップグレードされたかどうかにかかわらず、彼のバージョン番号が変わらない限り、シーケンス化メカニズムは彼らを同じシーケンス化バージョンと見なします.
ここで厳粛に自分を批判して、毎日Javabeanを書いて、毎回すべてそのserialVersionUIDを生成するのが面倒だと感じて、myeclipseを設置してこのバージョン番号を提示しないで、この習慣はよくなくて、必ず直して、また、引用のJavaの対象を使う時、すべての種類をSerializableインタフェースを実現することに注意して、これにより、シーケンス化と逆シーケンス化が正常であることが保証されます.クラスのフィールドが基本データ型またはStringでない場合 を選択します.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
*
* @version 1L
* @author LinkinPark
* @since 2014-12-31
* @motto ,
* @desc ^ , IO ,
*/
public class Linkin
{
public static void main(String[] args) throws Exception
{
// ObjectOutputStream , ,
ObjectOutputStream oos = null;
// ObjectInputStream , ,
ObjectInputStream ois = null;
try
{
//
oos = new ObjectOutputStream(new FileOutputStream("src/LinkinPark..."));
Person person = new Person();
person.setName("LinkinPark...");
person.setAge(25);
oos.writeObject(person);
// 2 ,
oos = new ObjectOutputStream(new FileOutputStream("src/LinkinPark1..."));
oos.writeObject(person);
ois = new ObjectInputStream(new FileInputStream("src/LinkinPark..."));
Person person1 = (Person) ois.readObject();
System.out.println(" :" + person1.getName() + ";" + person1.getAge());
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (oos != null)
{
oos.close();
}
if (ois != null)
{
ois.close();
}
}
}
}
// , Serializable , IDE ,
class Person implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
public Person()
{
//
System.out.println(" Java , ");
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public Integer getAge()
{
return age;
}
public void setAge(Integer age)
{
this.age = age;
}
}
2つの方法があります.
1,この比較的簡単なのは,シーケンス化を望まない属性の前にtransientを付けるとよい.注意:transientは属性を修飾するためにのみ使用でき、Javaの他のメンバーを修飾することはできません.この方法を使用すると便利ですが、transientによって修飾された属性がシーケンス化メカニズムから完全に分離されているという欠点があります.これにより、逆シーケンス化がJavaオブジェクトを復元する際にその属性値を取得できなくなります.
2.プログラムは、シーケンス化メカニズムをカスタマイズすることによって、各成分をどのようにシーケンス化するかを制御することができる.特殊な処理が必要なクラスに以下の3つの方法を提供すれば実現できるが,使用シナリオはそれほど多くなく,理解すればよい.private void wirteObject(Object OutputStream out):ライトオブジェクトprivate void readObject(Object InputStream in):リードオブジェクトprivate void readObject ObjectNoData()シーケンスフローが不完全な場合、逆シーケンス化されたオブジェクトを正しく初期化します.