53

クライアントとサーバーを作成し、シリアル化の目的でクライアント側にクラスを追加しました。次に、ハードドライブ内のクライアントのフォルダーに移動し、サーバーの対応する場所にそれぞれコピーして貼り付けましclassname.classclassname.java

自分のラップトップではうまく機能しましたが、他のシステムで作業を続けたい場合、プロジェクトフォルダーを開いたとき、クライアントがサーバーに接続しようとした後、次のエラーが表示されます。

Exception in thread "main" java.io.InvalidClassException: projectname.clasname; local class incompatible: stream classdesc serialVersionUID = -6009442170907349114, local class serialVersionUID = 6529685098267757690
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)

何が起こっている?古いバージョンのIDEでプログラムを実行したためですか?

編集

import java.io.Serializable;
import java.net.URL;

public class KeyAdr implements Serializable {
  private static final long serialVersionUID = 6529685098267757690L;

  public URL adr;
  public String key;
}
4

8 に答える 8

73

クラスがコードで明示的に定義していない場合、private static final long serialVersionUIDそれは自動生成され、異なるマシンが同じIDを生成するという保証はありません。それがまさに起こったことのようです。また、クラスが何らかの形で異なる場合(クラスの異なるバージョンを使用)、自動生成serialVersionUIDされたも異なります。

Serializableインターフェイスのドキュメントから:

シリアル化可能なクラスが明示的に宣言していない場合、シリアルserialVersionUID化ランタイムはserialVersionUID、Java(TM)オブジェクトのシリアル化仕様で説明されているように、クラスのさまざまな側面に基づいてそのクラスのデフォルト値を計算します。ただし、デフォルトの計算はコンパイラの実装によって異なる可能性のあるクラスの詳細に非常に敏感であり、逆シリアル化中に予期しない結果になる可能性があるため、すべてのシリアル化可能なクラスで値を明示的に宣言することを強くお勧めします。したがって、異なるJavaコンパイラの実装間で一貫した値を保証するには、シリアライズ可能なクラスで明示的な値を宣言する必要があります。また、明示的にすることを強くお勧めしますserialVersionUIDserialVersionUIDInvalidClassExceptionsserialVersionUIDserialVersionUIDserialVersionUIDprivateこのような宣言はすぐに宣言するクラスにのみ適用されるため、宣言では可能な場合は修飾子を使用しserialVersionUIDます。フィールドは継承されたメンバーとしては役立ちません。配列クラスは明示的なを宣言できないserialVersionUIDため、常にデフォルトの計算値がありますが、serialVersionUID配列クラスの値を一致させる必要はありません。

serialVersionUIDクラス定義でを定義する必要があります。例:

class MyClass implements Serializable {
    private static final long serialVersionUID = 6529685098267757690L;
    ...
于 2012-04-30T05:29:08.307 に答える
8

発生した可能性のある1つのこと:

  • 1:特定のライブラリA(バージョンX)を使用してシリアル化されたデータを作成します
  • 2:次に、同じライブラリA(ただしバージョンY)でこのデータを読み取ろうとします

したがって、バージョンXのコンパイル時に、JVMは最初のシリアルID(バージョンXの場合)を生成し、他のバージョンY(別のシリアルID)でも同じことを行います。

プログラムがデータを逆シリアル化しようとすると、2つのクラスが同じシリアルIDを持たず、プログラムは2つのシリアル化されたオブジェクトが同じクラス形式に対応することを保証しないため、逆シリアル化できません。

その間にコンストラクターを変更し、これが理にかなっていると仮定します。

于 2018-03-14T09:52:48.410 に答える
1

Eclipse IDEを使用している場合は、デバッグ/実行構成を確認してください。[クラスパス]タブで、ランナープロジェクトを選択し、[編集]ボタンをクリックします。 チェックする必要があるのは、エクスポートされたエントリのみを含めることです。

于 2020-02-03T08:12:17.963 に答える
0

Javaでのシリアル化は、長期的な永続性やトランスポート形式を意味するものではありません。これには脆弱すぎます。クラスバイトコードとJVMにわずかな違いがあるため、データを読み取ることができなくなります。タスクにXMLまたはJSONデータバインディングを使用します(XStreamは高速で使いやすく、代替手段がたくさんあります)

于 2012-04-30T06:05:51.573 に答える
0

これは、クライアントとサーバーで同じクラスの異なるバージョンを使用しているために発生すると思います。異なるデータフィールドまたはメソッドにすることができます

于 2012-04-30T05:29:35.590 に答える
0

例外メッセージは、クラスメタデータも含むクラスバージョンが時間の経過とともに変更されたことを明確に示しています。つまり、シリアル化中のクラス構造は、逆シリアル化中と同じではありません。これはおそらく「進行中」です。

于 2015-03-08T15:39:23.203 に答える
0

oc4jを使用してearをデプロイしている場合。

プロジェクトにdeploy.home=の正しいパスを設定していることを確認してください

common.propertiesファイルでdeploy.homeを見つけることができます

サーバークラスとクライアントクラスが同じserialVersionUIDを持つように、oc4jは新しく作成されたクラスをearにリロードする必要があります

于 2019-07-24T07:31:59.130 に答える
0

IntelliJ IDEAを使用している場合は、[ファイル]->[キャッシュの無効化]に移動します。これにより、この問題を引き起こす可能性のあるキャッシュされたクラスがすべてクリアされます。

于 2021-07-06T13:49:12.343 に答える