Javaラーニング(16):Javaシーケンス化とクローン化


Serializableインタフェース
シーケンス化:オブジェクトの寿命は、通常、そのオブジェクトを生成するプログラムの終了に伴って終了します.メモリ内のさまざまなオブジェクトの状態を(つまり、インスタンス変数はメソッドではなく)保存され、必要に応じてオブジェクトを復元できます.オブジェクトの状態を保存するには、さまざまな方法がありますが、Javaはオブジェクトのデータ、関連オブジェクトを含むオブジェクトを1バイトシーケンスとして表すことができるオブジェクトシーケンス化のメカニズムを提供します.の各見出しページがあります.
シーケンス化されたオブジェクトをファイルに書き込むと、ファイルから読み出し、逆シーケンス化できます.すなわち、オブジェクトのタイプ情報、オブジェクトのデータ、およびオブジェクトのデータ型をメモリに新しいオブジェクトを作成するために使用できます.
プロセス全体はJava仮想マシン(JVM)によって独立しています.つまり、あるプラットフォーム上でシーケンス化されたオブジェクトは、別のまったく異なるプラットフォーム上でそのオブジェクトを逆シーケンス化することができます.
シーケンス化の目的
  • メモリ内のオブジェクト状態を1つのファイルまたはデータベースに保存したい場合
  • 対象をネットワークを介して伝播しようとしたとき
  • .
    クラスObjectInputStreamおよびObjectOutputStreamは、オブジェクトを逆シーケンス化およびシーケンス化する方法を含む高レベルのデータ・ストリームです.
    ObjectOutputStreamクラスには、さまざまなデータ型を書くための多くの書き込み方法が含まれていますが、特別な方法の例外です.
    public final void writeObject(Object x) throws IOException
    上記の方法では、オブジェクトをシーケンス化し、出力ストリームに送信します.同様のObjectInputStreamクラスには、次のようにオブジェクトを逆シーケンス化する方法があります.
    public final Object readObject()throws IOException, ClassNotFoundException
    このメソッドは、ストリームから次のオブジェクトを取り出し、オブジェクトを逆シーケンス化します.戻り値はObjectなので、適切なデータ型に変換する必要があります.
    シーケンス化の方法
    Serializableインタフェースを実装するクラスが1つあれば、このクラスはシーケンス化できます.
    class Person implements Serializable{	
    	private static final long serialVersionUID = 1L; //           
    	String name;
    	int age;
    	public Person(String name,int age){
    		this.name = name;
    		this.age = age;
    	}	
    	public String toString(){
    		return "name:"+name+"\tage:"+age;
    	}
    }

    クラスのオブジェクトをシーケンス化するには、次の2つの条件を満たす必要があります.
    このクラスはjavaを実装必要がある.io.Serializableオブジェクト.
    クラスのすべてのプロパティはシーケンス可能である必要があります.シーケンス可能でない属性がある場合は、その属性に短いことを明記する必要があります.
    Java標準クラスがシーケンス可能かどうかを知りたい場合は、クラスのドキュメントを参照してください.クラスのインスタンスがシーケンス化できるかどうかを確認するのは簡単で、javaが実装されているかどうかを確認するだけです.io.Serializableインタフェース.
    このクラスのオブジェクトをObjectOutputStreamのwriteObject()メソッドで1つの場所(ファイル)に書き、ObjectInputStreamのreadObject()メソッドでこのオブジェクトを読み出します.
    File file = new File("file"+File.separator+"out.txt");
    	
    	FileOutputStream fos = null;
    	try {
    		fos = new FileOutputStream(file);
    		ObjectOutputStream oos = null;
    		try {
    			oos = new ObjectOutputStream(fos);
    			Person person = new Person("tom", 22);
    			System.out.println(person);
    			oos.writeObject(person);			//          
    			oos.flush();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}finally{
    			try {
    				oos.close();
    			} catch (IOException e) {
    				System.out.println("oos    :"+e.getMessage());
    			}
    		}
    	} catch (FileNotFoundException e) {
    		System.out.println("     :"+e.getMessage());
    	} finally{
    		try {
    			fos.close();
    		} catch (IOException e) {
    			System.out.println("fos    :"+e.getMessage());
    		}
    	}
    							
    	FileInputStream fis = null;
    	try {
    		fis = new FileInputStream(file);
    		ObjectInputStream ois = null;
    		try {
    			ois = new ObjectInputStream(fis);
    		try {
    				Person person = (Person)ois.readObject();	//         
    				System.out.println(person);
    			} catch (ClassNotFoundException e) {
    				e.printStackTrace();
    			} 
    		} catch (IOException e) {
    			e.printStackTrace();
    		}finally{
    			try {
    				ois.close();
    			} catch (IOException e) {
    				System.out.println("ois    :"+e.getMessage());
    			}
    		}
    	} catch (FileNotFoundException e) {
    		System.out.println("     :"+e.getMessage());
    	} finally{
    		try {
    			fis.close();
    		} catch (IOException e) {
    			System.out.println("fis    :"+e.getMessage());
    		}
    	}

     
    ここでは、以下のポイントに注意してください.
    readObject()メソッドのtry/catchコードブロックはClassNotFoundException例外をキャプチャしようとします.JVMがオブジェクトを逆シーケンスできる場合は、バイトコードを見つけることができるクラスである必要があります.JVMが逆シーケンス化オブジェクト中にクラスが見つからない場合は、ClassNotFoundException例外が放出されます.Personクラスのimplements Serializableを削除すると、Personクラスはシーケンス化できません.このとき上記のプログラムを再実行するとjavaが報告する.io.NotSerializableException異常.
    serialVersionUID
    上記のプログラムにserialVersionUIDがあることに気づき、Serializableインタフェースを実現すると、EclipseはserialVersionUIDを追加するように要求します.追加しないと上記のプログラムは正常に動作します.
    シーケンスIDはEclipseの下で2つの生成ポリシーを提供する
  • 一つは固定1 L
  • は、重複しないlongタイプのデータをランダムに生成する(実際にはJDKツールを使用し、クラス名、インタフェース名、メンバーメソッド、属性などに基づいて生成される)
  • である.
    上記のプログラムでは、出力オブジェクトと読み込みオブジェクトは同じPersonクラスを使用しています.
    ネットワークを介して伝送される場合,PersonクラスのserialVersionUIDが一致しなければ,逆シーケンス化は正常に行われない.例えば、クライアントAにおいてPersonクラスのserialVersionUID=1 L、クライアントBにおいてPersonクラスのserialVersionUID=2 Lでは、このPersonオブジェクトを再構築することはできない.では、ランダムに生成されるシーケンス化IDはどのような役割を果たすのでしょうか.シーケンス化IDを変更することで、一部のユーザーの使用を制限することができる場合があります.
    Javaでのシーケンス化と逆シーケンス化について
    シーケンス化については、永続化とも呼ばれ、ディスクに書き込まれます.
    さらに、符号化ルールについては、
    いずれかのエンティティークラスは、後でクラスを永続化したり、ネットワーク転送のためにバイト配列に変換したりするためにSerializableインタフェースを実装する必要があります.
    エンティティクラスの場合、すべてのプロパティをシーケンス化したくない場合は、専用のキーワードtransientがあります.
    private transient String name;
    クラスをシーケンス化すると、transientによって修飾されたプロパティは自動的に無視されます.
    Transientキーワードの役割は、インスタンスでこのキーワードで宣言された変数の永続化を阻止することです.オブジェクトが逆シーケンス化されると(ソースファイルからバイトシーケンスが読み込まれて再構築される)、このようなインスタンス変数値は永続化されず、復元されません.
    シーケンス化はオブジェクトの状態を保存し、静的変数はクラスの状態に属するため、シーケンス化は静的変数を保存しません.
    注意:一部のタイプのプロパティでは、ステータスは瞬時であり、そのプロパティはステータスを保存できません.たとえば、スレッド属性やIO、ローカルリソース、ネットワークリソースなどにアクセスする必要がある属性など、これらのフィールドについてはtransientキーワードで明記する必要があります.そうしないと、コンパイラは対処します.
    シーケンス化での継承の問題
  • 親クラスがシーケンス化されると、サブクラスは自動的にシーケンス化され、Serializableインタフェースを明示的に実装する必要はありません.
  • サブクラスはSerializableインタフェースを実装し、その親クラスはSerializableインタフェースを実装していない.親オブジェクトもシーケンス化するには、親クラスにもSerializableインタフェースを実装させる必要がある.

  • まとめ
    シーケンス化は、オブジェクトの変数を保存するための技術を提供します.転送を容易にします.
     
    Cloneableインタフェース
    clone:スタック内で元のオブジェクトと同じオブジェクトをクローン化し、そのオブジェクトのアドレスに新しい参照を付与できます. 
    Javaのクラスでclone機能を実装するには、Cloneableインタフェースを実装する必要があります.そうしないと、clone()を呼び出すと、CloneNotSupportedException例外が報告されます.
    Javaのすべてのクラスはjavaをデフォルトで継承します.lang.Objectクラスjava.lang.Objectクラスには、Objectオブジェクトのコピーを返すメソッドclone()があります. .
    浅いレプリケーション
    class CloneClass implements Cloneable{
     public int aInt;
     public Object clone(){
      CloneClass o = null;
      try{
       o = (CloneClass)super.clone();
      }catch(CloneNotSupportedException e){
       e.printStackTrace();
      }
      return o;
     }
    }

    深くコピー
    public Object clone() throws CloneNotSupportedException{
            Student newStudent = (CloneClass) super.clone();
            newStudent.professor = (Professor) professor.clone();
            return newStudent;
        }

     
    注意すべき点は3つあります.
    1つはclone機能を実現するために、CloneClassクラスはCloneableインタフェースコピーオブジェクトが参照ではなく新しいオブジェクトを返すことを実現した.
    二つ目はclone()を再ロードする方法です. 
    3つ目はclone()メソッドでsuperを呼び出すことです.clone()は、cloneクラスの継承構造がどのようなものであっても、super.clone()はjavaを直接または間接的に呼び出した.lang.Objectクラスのclone()メソッド.
    Objectクラスのclone()メソッドはnativeメソッドであり,nativeメソッドの効率は一般的にjavaの非nativeメソッドよりはるかに高い.これは、新しいオブジェクトに元のオブジェクトの情報を割り当てるのではなく、Objectのclone()メソッドを使用する理由を説明します.
    Objectクラスのclone()メソッドはprotectedプロパティのメソッドです.つまり、clone()メソッドを適用する場合は、Objectクラスを継承し、リロード後にclone()メソッドのプロパティをpublicに設定する必要があります.