JavaのSerializable
との違いは何ですか?Externalizable
11 に答える
Serializable
との主な違いExternalizable
- マーカー インターフェイス:
Serializable
メソッドのないマーカー インターフェイスです。Externalizable
インターフェイスにはwriteExternal()
、 との 2 つのメソッドが含まれていますreadExternal()
。 - シリアライゼーション プロセス: デフォルトのシリアライゼーション プロセスは、
Serializable
インターフェイスを実装するクラスに対して開始されます。プログラマ定義のシリアル化プロセスは、インターフェイスを実装するクラスに対して開始されExternalizable
ます。 - メンテナンス:互換性のない変更により、シリアル化が壊れる可能性があります。
- 下位互換性と制御: 複数のバージョンをサポートする必要がある場合は、
Externalizable
インターフェイスを使用して完全に制御できます。オブジェクトのさまざまなバージョンをサポートできます。を実装する場合、クラスExternalizable
をシリアライズするのはあなたの責任ですsuper
- public No-arg constructor :
Serializable
リフレクションを使用してオブジェクトを構築し、arg コンストラクターを必要としません。ただし、Externalizable
パブリックの引数なしコンストラクターが必要です。
詳細については、ブログbyHitesh Garg
を参照してください。
シリアル化では、特定の既定の動作を使用してオブジェクトを保存し、後で再作成します。参照や複雑なデータ構造を処理する順序や方法を指定することはできますが、最終的には、各プリミティブ データ フィールドに対してデフォルトの動作を使用することになります。
外部化は、データ フィールドのデフォルトのシリアル化メカニズムを使用せずに、まったく異なる方法でオブジェクトを格納および再構築したいというまれなケースで使用されます。たとえば、独自のエンコード方式と圧縮方式があるとします。
オブジェクトのシリアル化は、Serializable および Externalizable インターフェイスを使用します。 Java オブジェクトは直列化のみ可能です。クラスまたはそのスーパークラスのいずれかが java.io.Serializable インターフェースまたはそのサブインターフェースである java.io.Externalizable を実装している場合。ほとんどの Java クラスはシリアライズ可能です。
NotSerializableException
:packageName.ClassName
« クラス オブジェクトをシリアル化プロセスに参加させるには, クラスは Serializable または Externalizable インターフェイスを実装する必要があります.
オブジェクトのシリアライゼーションは、保存されるオブジェクトの Java クラスに関する情報を含むストリームを生成します。直列化可能なオブジェクトの場合、クラスの実装の異なる (ただし互換性のある) バージョンが存在する場合でも、それらのオブジェクトを復元するのに十分な情報が保持されます。Serializable インターフェースは、シリアライズ可能なプロトコルを実装するクラスを識別するために定義されています。
package java.io;
public interface Serializable {};
- シリアライゼーション インターフェイスにはメソッドやフィールドがなく、シリアライズ可能であることのセマンティクスを識別するためだけに機能します。クラスをシリアライズ/デシリアライズするには、デフォルトの writeObject および readObject メソッドを使用できます (または) クラスから writeObject および readObject メソッドをオーバーライドできます。
- JVM は、オブジェクトのシリアル化を完全に制御します。データ メンバーがシリアル化されないようにするには、transient キーワードを使用します。
- ここで、シリアライズ可能なオブジェクトは、実行せずにストリームから直接再構築されます
InvalidClassException
« デシリアライズ処理において、ローカルクラスのserialVersionUID値が対応する送信者のクラスと異なる場合。結果は次のように競合しますjava.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
- クラスの非一時的および非静的フィールドの値はシリアル化されます。
外部化可能オブジェクトの場合、オブジェクトのクラスの ID のみがコンテナーによって保存されます。クラスは内容を保存して復元する必要があります。Externalizable インターフェイスは次のように定義されます。
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
- Externalizable インターフェイスには 2 つのメソッドがあります。外部化可能オブジェクトは、オブジェクトの状態を保存/復元するために writeExternal メソッドと readExternal メソッドを実装する必要があります。
- プログラマーは、シリアライズするオブジェクトを処理する必要があります。プログラマーとしてシリアライゼーションの世話をするので、ここで一時的なキーワードは、シリアライゼーション プロセスのオブジェクトを制限しません。
- Externalizable オブジェクトが再構築されると、引数なしの public コンストラクターを使用してインスタンスが作成され、次に readExternal メソッドが呼び出されます。直列化可能なオブジェクトは、ObjectInputStream から読み取ることによって復元されます。
OptionalDataException
« フィールドは、書き出されたものと同じ順序とタイプでなければなりません。ストリームからのタイプの不一致がある場合、OptionalDataException がスローされます。@Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt( id ); out.writeUTF( role ); out.writeObject(address); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.id = in.readInt(); this.address = (Address) in.readObject(); this.role = in.readUTF(); }
シリアル化されるように記述(公開)されたクラスのインスタンス フィールド
ObjectOutput
。
例« Serializable を実装します
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
例«は Externalizable を実装します
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
例
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@見る
シリアル化プロセスのパフォーマンスを最適化するために、Externalizableインターフェイスは実際には提供されていません。ただし、独自のカスタム処理を実装する手段を提供し、オブジェクトとそのスーパータイプのストリームの形式と内容を完全に制御できるようにするためです。
この例は、ネットワークを介してネイティブアクションスクリプトオブジェクトを転送するためのAMF(ActionScriptメッセージフォーマット)リモーティングの実装です。
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
デフォルトのシリアライゼーションはやや冗長であり、シリアライズされたオブジェクトの可能な限り幅広い使用シナリオを想定しているため、デフォルトの形式 (Serializable) では、結果のストリームにシリアライズされたオブジェクトのクラスに関する情報が注釈として付けられます。
外部化により、オブジェクト ストリームの作成者は、必要最小限のクラスの識別情報 (名前など) を超えて、正確なクラス メタデータ (存在する場合) を完全に制御できます。これは、オブジェクト ストリームのプロデューサーとそのコンシューマー (ストリームからオブジェクトを具体化する) が一致し、クラスに関する追加のメタデータが目的を果たさず、パフォーマンスを低下させる、クローズド環境などの特定の状況では明らかに望ましいものです。
さらに (Uri が指摘するように) 外部化により、Java 型に対応するストリーム内のデータのエンコードを完全に制御することもできます。(不自然な) 例として、ブール値の true を「Y」、false を「N」として記録したい場合があります。それを可能にするのが外部化です。
パフォーマンスを向上させるためのオプションを検討するときは、カスタムのシリアル化を忘れないでください。Java がうまく機能すること、または少なくとも十分に機能することを無料で実行し、Java がうまく機能しないことについてはカスタム サポートを提供できます。これは通常、Externalizable を完全にサポートするよりもはるかに少ないコードです。
いくつかの違い:
シリアライゼーションの場合、Object は JVM が Reflection API を使用して同じように構築するため、そのクラスのデフォルト コンストラクターは必要ありません。外部化の場合、引数のないコンストラクターが必要です。これは、コントロールがプログラマーの手にあり、後でセッターを介して逆シリアル化されたデータをオブジェクトに割り当てるためです。
シリアライゼーションでは、ユーザーがシリアライズする特定のプロパティをスキップしたい場合、そのプロパティを一時的なものとしてマークする必要があります。その逆は、外部化では必要ありません。
どのクラスでも下位互換性のサポートが期待される場合は、Externalizable を使用することをお勧めします。シリアル化は defaultObject の永続化をサポートしており、オブジェクト構造が壊れていると、逆シリアル化中に問題が発生します。