違いは何であるSerializable
とExternalizable
Javaでは?
違いは何であるSerializable
とExternalizable
Javaでは?
回答:
他の回答に追加するには、を実装java.io.Serializable
することで、クラスのオブジェクトの「自動」シリアル化機能を利用できます。他のロジックを実装する必要はありません。機能します。Javaランタイムはリフレクションを使用して、オブジェクトをマーシャリングおよびマーシャリング解除する方法を理解します。
以前のバージョンのJavaでは、リフレクションが非常に遅いため、大きなオブジェクトグラフ(クライアント/サーバーRMIアプリケーションなど)のシリアル化は、パフォーマンスの問題の少しでした。この状況に対処するために、java.io.Externalizable
インターフェイスが提供されました。これはjava.io.Serializable
、マーシャリング機能とアンマーシャリング機能を実行するためのカスタム作成メカニズムに似ていますが、クラスにメソッドreadExternal
とwriteExternal
メソッドを実装する必要があります。これにより、反射パフォーマンスのボトルネックを回避する手段が得られます。
Javaの最近のバージョン(1.3以降)では、リフレクションのパフォーマンスは以前よりもはるかに優れているため、問題ははるかに少なくなります。Externalizable
最近のJVMで意味のある利益を得るのは難しいでしょう。
また、組み込みのJavaシリアライゼーションメカニズムだけではなく、JBoss Serializationなどのサードパーティの置き換えを利用できます。これはかなり高速で、デフォルトのドロップイン置き換えです。
の大きな欠点Externalizable
は、このロジックを自分で維持する必要があることです。クラスのフィールドを追加、削除、または変更した場合は、それを説明するためにwriteExternal
/ readExternal
メソッドを変更する必要があります。
要約Externalizable
すると、Java 1.1の遺物です。本当にそれはもう必要ありません。
Externalizable
は、非常に役立ちます。
Externalizable
空のスペースやプレースホルダーオブジェクトを含む配列を出力したくないので、カスタムコレクションを作成する必要があり、それがはるかに適していると言う必要があります。また、明示的なインターフェイスを使用すると、継承を処理できます。つまり、同期されたサブ-classは、への呼び出しの周りに簡単にロックを追加できますwriteExternal()
。そのため、そうです、Externalizableは、非常に関連性が高く、確かに大きなオブジェクトや複雑なオブジェクトに適しています。
シリアライゼーションは、オブジェクトを保存して後で再作成するデフォルトの機能を提供します。これは冗長形式を使用して、格納するオブジェクトのグラフ全体を定義します。たとえば、linkedListがあり、以下のようなコードを記述した場合、デフォルトのシリアル化により、リンクされているすべてのオブジェクトが検出され、シリアル化されます。デフォルトのシリアル化では、オブジェクトは、コンストラクター呼び出しなしで、格納されたビットから完全に構築されます。
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
ただし、シリアル化を制限したい場合、またはオブジェクトの一部をシリアル化したくない場合は、Externalizableを使用します。ExternalizableインターフェースはSerializableインターフェースを拡張し、writeExternal()およびreadExternal()という2つのメソッドを追加します。これらは、シリアライズまたはデシリアライズ中に自動的に呼び出されます。Externalizableを使用するときは、デフォルトのコンストラクターをパブリックにする必要があることを忘れないでください。そうしないと、コードが例外をスローします。以下のコードに従ってください:
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
ここで、デフォルトのコンストラクタをコメントすると、コードは例外の下でスローされます。
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
パスワードは機密情報であるため、writeExternal(ObjectOutput oo)メソッドでシリアル化せず、readExternal(ObjectInput oi)で同じ値を設定していないことを確認できます。それがExternalizableによって提供される柔軟性です。
上記のコードの出力は以下の通りです:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
passWordの値を設定していないため、nullであることがわかります。
同じことは、パスワードフィールドを一時的なものとして宣言することによっても実現できます。
private transient String passWord;
それが役に立てば幸い。間違えた場合はお詫び申し上げます。ありがとう。
主な違いSerializable
とExternalizable
Serializable
メソッドのないマーカーインターフェイスです。Externalizable
インターフェイスには2つのメソッドが含まれています:writeExternal()
およびreadExternal()
。Serializable
インターフェイスを実装するクラスのデフォルトのシリアル化プロセスが開始されます。プログラマー定義のシリアライゼーションプロセスは、Externalizable
インターフェイスを実装するクラスに組み込まれます。Externalizable
インターフェースで完全に制御できます。オブジェクトのさまざまなバージョンをサポートできます。を実装する場合Externalizable
、super
クラスをシリアライズするのはあなたの責任ですSerializable
オブジェクトを構築するためにリフレクションを使用し、引数のコンストラクタを必要としません。ただし、Externalizable
引数なしのパブリックコンストラクタが必要です。参照してくださいブログでHitesh Garg
詳細は。
シリアライゼーションは、特定のデフォルトの動作を使用してオブジェクトを保存し、後で再作成します。参照と複雑なデータ構造を処理する順序または方法を指定できますが、最終的には各プリミティブデータフィールドのデフォルトの動作を使用することになります。
外部化は、オブジェクトを完全に異なる方法で保存および再構築したい場合に、データフィールドのデフォルトのシリアル化メカニズムを使用せずに、まれに使用されます。たとえば、独自のエンコードおよび圧縮スキームを使用しているとしましょう。
オブジェクトの直列化は、直列化可能および外部化可能インターフェースを使用します。 Javaオブジェクトはシリアル化のみ可能です。クラスまたはそのスーパークラスのいずれかがjava.io.Serializableインターフェースまたはそのサブインターフェースjava.io.Externalizableを実装する場合。ほとんどのJavaクラスはシリアライズ可能です。
NotSerializableException
:packageName.ClassName
«クラスオブジェクトをシリアル化プロセスに参加させるには、クラスがSerializableまたはExternalizableインターフェイスを実装する必要があります。オブジェクト直列化は、保存されているオブジェクトのJavaクラスに関する情報を含むストリームを生成します。シリアライズ可能なオブジェクトの場合、クラスの実装の異なる(ただし互換性のある)バージョンが存在する場合でも、それらのオブジェクトを復元するために十分な情報が保持されます。Serializableインターフェースは、直列化可能プロトコルを実装するクラスを識別するために定義されています。
package java.io;
public interface Serializable {};
InvalidClassException
«逆シリアル化プロセスで、ローカルクラスのserialVersionUID値が対応する送信者のクラスと異なる場合。結果は次のように競合します
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Externalizableオブジェクトの場合、オブジェクトのクラスの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;
}
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();
}
}
}
@見る
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
デフォルトのシリアル化はいくぶん冗長であり、シリアル化されたオブジェクトの可能な最も広い使用シナリオを想定しているため、デフォルトの形式(Serializable)は、結果のストリームにシリアル化されたオブジェクトのクラスに関する情報を注釈します。
外部化により、オブジェクトストリームのプロデューサーは、クラスの必要最小限の識別(例:名前)を超えて、正確なクラスメタデータ(存在する場合)を完全に制御できます。これは、オブジェクトストリームのプロデューサーとそのコンシューマー(ストリームからオブジェクトを具体化する)が一致し、クラスに関する追加のメタデータが目的を果たさず、パフォーマンスを低下させる、閉じた環境などの特定の状況では明らかに望ましいです。
さらに、(Uriが指摘しているように)外部化により、Java型に対応するストリーム内のデータのエンコードを完全に制御することもできます。(不自然な)例の場合、ブール値のtrueを「Y」、falseを「N」として記録できます。外部化はそれを可能にします。
SerializableとExternalizableの間には非常に多くの違いがありますが、カスタムSerializable(overrided writeObject()&readObject())とExternalizableの違いを比較すると、カスタム実装が、Externalizableの場合のように、ObjectOutputStreamクラスと緊密にバインドされていることがわかります。 ObjectOutputStreamクラスであるか、org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStreamのようなObjectOutputの実装を提供する
外部化可能インターフェースの場合
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
わかりやすく説明するためにサンプルコードを追加しました。Externalizableのオブジェクトケースをチェックイン/チェックアウトしてください。これらは、どの実装にも直接バインドされていません。
Outstream / Instreamがクラスにしっかりとバインドされている場合。ObjectOutputStream / ObjectInputStreamを拡張できますが、使用するのが少し難しくなります。
基本的にSerializable
は、クラスがシリアル化に対して安全であり、JVMがクラスのシリアル化方法を決定することを意味するマーカーインターフェイスです。Externalizable
2つのメソッドが含まれ、readExternal
そしてwriteExternal
。Externalizable
オブジェクトをシリアル化する方法を実装者が決定できるようにしますSerializable
。デフォルトでは、オブジェクトをシリアル化します。
いくつかの違い:
シリアライゼーションの場合、JVMはリフレクションAPIを使用して同じように構築するので、オブジェクトはそのクラスのデフォルトコンストラクターの必要はありません。引数のない外部化コンストラクターが必要なのは、コントロールがプログラマーの手元にあり、後で逆シリアル化されたデータをセッターを介してオブジェクトに割り当てるためです。
シリアル化では、ユーザーが特定のプロパティをスキップしてシリアル化する必要がある場合、そのプロパティを一時的としてマークする必要があります。その逆は、外部化には必要ありません。
どのクラスでも下位互換性のサポートが期待される場合は、Externalizableを使用することをお勧めします。シリアル化はdefaultObjectの永続化をサポートしており、オブジェクト構造が壊れている場合、逆シリアル化中に問題が発生します。