web-dev-qa-db-ja.com

Serializableはどういう意味ですか?

JavaでクラスがSerializableであるとはどういう意味ですか?または一般的に、その問題については...

124
Ritwik Bose

シリアル化 は、たとえばディスクに保存するために、オブジェクトをメモリからビットシーケンスに永続化します。逆シリアル化は反対です-オブジェクトをハイドレート/作成するためにディスクからデータを読み取ります。

質問のコンテキストでは、クラスに実装されている場合、このクラスはさまざまなシリアライザーによって自動的にシリアル化および逆シリアル化できるインターフェイスです。

120
Oded

ほとんどのユーザーはすでに答えを出していますが、アイデアを説明するためにそれを必要とする人のために例を追加したいと思います。

次のようなクラスの人がいるとしましょう:

public class Person implements Java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

次に、次のようなオブジェクトを作成します。

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

そのオブジェクトを多くのストリームにシリアル化できます。これを2つのストリームに行います。

標準出力へのシリアル化:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

ファイルへのシリアル化:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

次に:

ファイルからデシリアライズ:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }
37
William Kinaan

これは、クラスのインスタンスをバイトストリームに変換し(たとえば、ファイルに保存する)、その後再びクラスに変換できることを意味します。この再読み込みは、プログラムの別のインスタンス、または別のマシンでも発生する可能性があります。ただし、特にシリアル化可能なオブジェクト内の他のオブジェクトへの参照がある場合は、(あらゆる言語での)シリアル化にはあらゆる種類の問題が伴います。

35
David

シリアル化の詳細な説明 :(自分のブログ)

シリアル化:

シリアル化とは、オブジェクトの状態をシリアル化するプロセスであり、バイトシーケンスの形式で表現および格納されます。これはファイルに保存できます。ファイルからオブジェクトの状態を読み取り、復元するプロセスは、逆シリアル化と呼ばれます。

シリアル化の必要性は何ですか?

現代のアーキテクチャでは、オブジェクトの状態を保存してから取得する必要が常にあります。たとえば、Hibernateでは、オブジェクトを保存するには、クラスをSerializableにする必要があります。オブジェクトの状態がバイト形式で保存されると、別のシステムに転送できるようになり、その状態から読み取り、クラスを取得できるようになります。オブジェクトの状態は、データベース、別のjvm、または別のコンポーネントから取得できます。シリアル化の助けを借りて、オブジェクトの状態を取得できます。

コード例と説明:

まず、アイテムクラスを見てみましょう。

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

上記のコードでは、ItemクラスがSerializableを実装していることがわかります。

これは、クラスをシリアル化できるようにするインターフェイスです。

これで、serialVersionUIDという変数がLong変数に初期化されていることがわかります。この数は、クラスの状態とクラス属性に基づいてコンパイラーによって計算されます。これは、ファイルからオブジェクトの状態を読み取るときに、jvmがオブジェクトの状態を識別するのに役立つ番号です。

そのために、オラクルの公式ドキュメントを参照できます。

シリアル化ランタイムは、シリアル化可能なオブジェクトの送信者と受信者がシリアル化に関して互換性のあるオブジェクトのクラスをロードしたことを確認するために、シリアル化解除時に使用されるserialVersionUIDと呼ばれるバージョン番号を各シリアル化可能クラスに関連付けます。受信側が、対応する送信側のクラスとは異なるserialVersionUIDを持つオブジェクトのクラスをロードした場合、逆シリアル化によりInvalidClassExceptionが発生します。直列化可能クラスは、静的、final、およびlong型である必要がある「serialVersionUID」という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言できます。ANY-ACCESS-MODIFIER static final long直列化可能クラスが明示的にserialVersionUIDを宣言しない場合、直列化ランタイムは、Java(TM)Object Serialization Specificationで説明されているように、クラスのさまざまな側面に基づいてそのクラスのデフォルトのserialVersionUID値を計算します。ただし、デフォルトのserialVersionUID計算は、コンパイラーの実装によって異なる可能性のあるクラスの詳細に非常に敏感であり、その結果、逆シリアル化中に予期しないInvalidClassExceptionsが発生する可能性があるため、すべてのシリアル化可能なクラスが明示的にserialVersionUID値を宣言することを強くお勧めします。したがって、異なるJavaコンパイラー実装間で一貫したserialVersionUID値を保証するには、シリアライズ可能なクラスで明示的なserialVersionUID値を宣言する必要があります。また、明示的なserialVersionUID宣言は、可能な場合はprivate修飾子を使用することを強くお勧めします。このような宣言は、すぐに宣言するクラスにのみ適用されるためです。serialVersionUIDフィールドは、継承メンバーとしては役立ちません。

気づいたら、使用した別のキーワードtransientがあります。

フィールドがシリアル化可能でない場合は、一時的にマークする必要があります。ここでは、itemCostPriceを一時的なものとしてマークし、ファイルに書き込みたくない

次に、ファイル内のオブジェクトの状態を書き込み、そこから読み取る方法を見てみましょう。

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

上記では、オブジェクトのシリアル化と逆シリアル化の例を見ることができます。

そのために、2つのクラスを使用しました。オブジェクトをシリアル化するために、ObjectOutputStreamを使用しました。ファイルにオブジェクトを書き込むためにメソッドwriteObjectを使用しました。

デシリアライズには、ファイルからオブジェクトを読み取るObjectInputStreamを使用しました。 readObjectを使用して、ファイルからオブジェクトデータを読み取ります。

上記のコードの出力は次のようになります。

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

デシリアライズされたオブジェクトからのitemCostPriceは、書き込まれなかったため、nullであることに注意してください。

12
Pritam Banerjee

シリアル化では、オブジェクトの現在の状態をストリームに保存し、そのストリームから同等のオブジェクトを復元します。ストリームはオブジェクトのコンテナとして機能します

11
Jigar Joshi

Serializableはインターフェースのように呼び出されますが、コンパイラーへのフラグのようなものです。このオブジェクトは保存できると書かれています。シリアル化可能なオブジェクトとvolatileをマークするオブジェクトを除くすべてのObjectsインスタンス変数が保存されます。

あなたのアプリケーションはオプションとして色を変更できると想像してください。外部設定を維持せずに、実行するたびに色を変更する必要があります。

5
AphexMunky

シリアル化は、オブジェクトとデータをファイルに保存または書き込むための手法です。 ObjectOutputStreamおよびFileOutputStreamクラスを使用する。これらのクラスには、オブジェクトを永続化する特定のメソッドがあります。 writeObject();など

数字で明確に外植する。 詳細はこちらを参照

4
Mdhar9e

シリアル化:オブジェクトの状態をファイル/ネットワークまたはどこにでも書き込みます。 (平均Javaオブジェクトサポートフォームからファイルサポートフォームまたはネットワークサポートフォーム)

逆シリアル化:ファイル/ネットワークまたはどこからでもオブジェクトの状態を読み取ります。 (Java Objectサポートフォームへの平均ファイル/ネットワークサポートフォーム)

2
Asif Mushtaq

別の視点から提示する。シリアル化は、「マーカーインターフェイス」と呼ばれる一種のインターフェイスです。マーカーインターフェイスは、メソッドの宣言を含まないインターフェイスですが、インターフェイスを実装するクラスを何らかのプロパティを持つものとして指定(または「マーク」)するだけです。多型を理解していれば、これは非常に理にかなっています。 Serializableマーカーインターフェイスの場合、引数がインターフェイスを実装していない場合、ObjectOutputStream.write(Object)メソッドは失敗します。これはJavaの潜在的な間違いです。ObjectOutputStream.write(Serializable)である可能性があります。

強く推奨:詳細については、項目37をJoshua Blochによる効果的なJavaから読んでください。

2
nanospeck

他の答えに加えて、一般性に関して。シリアル化は、たとえばObjective-Cでアーカイブとして知られています。

0
Greg Sexton