Serializableの意味?


136

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


10
@skaffmanここでは、クラスのために言っていることだSerializableSerializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwikボーズ

32
シリアライズとデシリアライズの意味をすでに知っている場合の優れた説明。(褒め言葉ではありません。)このような定義は、問題を技術的に1回よりよく理解するのに役立ちます。
Xonatron、2012

回答:


132

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

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


2
また、明示的にマークされていないフィールドはすべてシリアル化されることにも注意してください。つまり、ルートオブジェクトをシリアル化するだけで、複雑なデータ構造を簡単に保存できます。
するThorbjörnRavnアンデルセン

1
「オブジェクト」について話しているとき、クラスによってインスタンス化されたオブジェクト、またはアセンブリやファイルなどの「ソフトウェアオブジェクト」だけを意味しているのでしょうか?後者の場合、それはプログラムと環境の間でデータを送信するための標準化された方法にすぎませんか?
Sunburst275

1
@ Sunburst275-この場合、これはメモリ内のクラスのメモリ内表現です。つまり、クラスのインスタンスです(アセンブリのシリアル化について話すのは本当の意味ではありません。アセンブリは通常、ファイルとしてディスク上にあるためです。そのまま送信されます)。
Oded

44

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

次のようなクラスの人がいるとします。

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();
    }

ありがとうございました。もうわかったと思います。
Sunburst275

40

つまり、クラスのインスタンスをバイトストリームに変換して(ファイルに保存するなど)、クラスに再度変換することができます。このリロードは、プログラムの別のインスタンスで、または別のマシンでも発生する可能性があります。(任意の言語での)シリアライゼーションには、特にシリアライズ可能なオブジェクト内の他のオブジェクトへの参照がある場合、あらゆる種類の問題が関係します。


15

ここにシリアライゼーションの詳細な説明があります:(私のブログ)

シリアル化:

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

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

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

コード例と説明:

まず、Itemクラスを見てみましょう。

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が発生します。直列化可能クラスは、静的、最終、およびlong型である必要がある「serialVersionUID」という名前のフィールドを宣言することにより、独自のserialVersionUIDを明示的に宣言できます。ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; シリアライズ可能なクラスがserialVersionUIDを明示的に宣言していない場合、次に、直列化ランタイムは、Java(TM)オブジェクト直列化仕様で説明されているように、クラスのさまざまな側面に基づいて、そのクラスのデフォルトのserialVersionUID値を計算します。ただし、デフォルトのserialVersionUIDの計算は、コンパイラーの実装によって異なる可能性があるクラスの詳細に非常に敏感であり、逆シリアル化中に予期しないInvalidClassExceptionsが発生する可能性があるため、すべてのシリアル化可能なクラスで明示的にserialVersionUID値を宣言することを強くお勧めします。したがって、さまざまなJavaコンパイラーの実装間で一貫したserialVersionUID値を保証するには、直列化可能クラスが明示的なserialVersionUID値を宣言する必要があります。また、可能であれば、明示的なserialVersionUID宣言でプライベート修飾子を使用することを強くお勧めします。

あなたが気づいたら、私たちが使用した別のキーワードが一時的です。

フィールドがシリアル化可能でない場合は、一時的としてマークする必要があります。ここでは、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であることに注意してください


2
詳しい説明ありがとうございます。
プレストンプレストン

これはいい説明です!ありがとうございました!しかし、正直に言うと、このエントリはブログのエントリよりもずっときれいに見えます。とにかく、これは大いに役立ちました!
Sunburst275

11

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


1
この定義はより正確に思われます。ありがとうございました。
プレストンプレストン

6

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

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


5
これは「コンパイラーへのフラグ」ではありません。これは、実行時のシリアル化サブシステムへのフラグです。
ローンの侯爵

1
@EJP-ありがとう、知りませんでした
AphexMunky 2010

敬意を表して、それが本当であると知らないときにそれを書くのはなぜですか また、「一過性」も除外しました。全体的に悪い答えです、すみません。
ローン侯爵

19
私がそれを書いたことがなかったら、私は修正されず、さらに悪くなるでしょう。他のすべての答えも一時的なものをやめました。あなたは答えさえ書いておらず、ただ他の人々を荒らしているだけです。
AphexMunky 2010

4

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

数字付きの明確な外植用。詳細はこちらをご覧ください


2

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

強く推奨:詳細については、Joshua BlochよるEffective Javaの Item 37を読んでください。


2

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

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


1

他の答えに加えて、一般性に関して。シリアル化は、たとえばObjective-Cでは、アーカイブと呼ばれることもあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.