不変の使用を目的としたクラスがあるため、すべてのフィールドにラベルを付けたいと思いますfinal
。
ただし、クラスはシリアル化および逆シリアル化されて、ネットワーク経由で送信されます。これが機能するには、空のコンストラクターが必要です。これにより、最終フィールドを作成できなくなります。
これはかなり一般的な問題だと思いますが、解決策が見つかりません。どうすればいいですか?
不変の使用を目的としたクラスがあるため、すべてのフィールドにラベルを付けたいと思いますfinal
。
ただし、クラスはシリアル化および逆シリアル化されて、ネットワーク経由で送信されます。これが機能するには、空のコンストラクターが必要です。これにより、最終フィールドを作成できなくなります。
これはかなり一般的な問題だと思いますが、解決策が見つかりません。どうすればいいですか?
引数なしのコンストラクターは必要ありません。最も派生したシリアル化不可能なクラスには、最も派生性の低いシリアル化可能なクラスで使用できる引数なしのコンストラクターが必要です。
内のフィールドを変更する必要がある場合は、およびreadObject
を介してシリアルプロキシを使用します。readResolve
writeReplace
通常のシリアル化の場合、シリアル化するためにクラスに空のコンストラクターまたは非最終フィールドがある必要はありません。
さて、独自のシリアル化を行う必要がある場合、またはSerializableを実装していないクラスをサブクラス化する必要がある場合、それは別の話です。
したがって、問題がどのように発生しているかについて、さらに詳細を提供する必要があります。
この問題は、Java言語の未解決のバグです。(これは、readObjectなどを使用して手動でシリアル化を行う必要がある場合にのみ適用されることに注意してください)
言われたことをエコーするために、インターフェースを実装するルートを取っている場合、引数なしのコンストラクターは要件ではありませんjava.io.Serializable
。たとえば、ソースコードを見てみましょうjava.lang.Integer
。2つのコンストラクターを持つ単純なシリアル化可能/不変クラスです。1つはintを取り、もう1つはStringを取ります。ソースコード: http: //www.docjar.com/html/api/java/lang/Integer.java.html。Javadoc: http: //java.sun.com/javase/6/docs/api/java/lang/Integer.html。
また、クラスの複雑さと実行していることによっては、java.io.Externalizable
インターフェイスを介してシリアル化を実装することを検討できます(ただし、一部のクラスは古くなっていると見なされ、引数なしのコンストラクターが必要です)。SOの概要は次のとおりです。JavaのSerializableとExternalizableの違いは何ですか?、およびこれが公式のJavaチュートリアルです:http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html。
ちなみに、同様の問題が発生したため、「 java.io.InvalidClassException:com.example.stuff.FooBar;com.example.stuff.FooBar;有効なコンストラクターがありません」
というメッセージが表示されました。
デフォルトのコンストラクターがなかったからだと思いました。しかし、上記の回答はそれが必須ではないことを確認しています(しかし、私たちのアプリは実際にデフォルトのコンストラクターを必要とする古いシリアライザーを使用しているため、ケースが発生する可能性があります)。
次に、次のようなページを見つけました。
継承用に設計されたクラスがシリアライズ可能でない場合、シリアライズ可能なサブクラスを作成できない可能性があります。具体的には、スーパークラスがアクセス可能なパラメーターなしのコンストラクターを提供しない場合は不可能です。
したがって、私が受け取ったメッセージは、私が思うに。コアの問題は古典的であるように見えました。クラスをシリアル化可能として宣言しましたが、スーパークラスはそうではありませんでした。Serializableインターフェースを階層の上位に移動しましたが、すべてうまくいきました。
しかし、メッセージは少し誤解を招くものでした... :-)
引数なしのコンストラクターは必要ありません。ソースコードを読んでみましょう:
// java.io.ObjectStreamClass
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
if ((initCl = initCl.getSuperclass()) == null) {
return null;
}
}
...
}
したがって、実際にはSerializable
、型階層内の最も近いnotクラスに引数なしのコンストラクターが必要です。
これは、次のクラスDomain
をシリアル化できることを意味します。
class Domain implements Serializable {
private final int a;
public Domain(int a) {
this.a = a;
}
}
しかし、クラスSon
はできません:
class Father{
private final int a;
public Father(int a) {
this.a = a;
}
}
class Son extends Father implements Serializable {
public Son(int a) {
super(a);
}
}