为什么我在尝试序列化对象时收到 NotSerializableException

Why I receive NotSerializableException while attempting to Serialize an Object

我有以下 class:

public class GameWorld implements Serializable {
    int sumu_dist = 30;
    public List<Tiles> tileGroup = new ArrayList<>();
    public List<Tiles> loadingTiles = new ArrayList<>();

    // constructor etc.
}

在另一个 class 中,我试图保存 GameWorld,但收到不可序列化的异常:

public class game {

    static GameWorld GameWorldObj = new GameWorld();

    String FileName = "WorldData.bin";

void Save(){
    try {
        FileOutputStream FOS = new FileOutputStream(FileName);
        ObjectOutputStream OOS = new ObjectOutputStream(FOS);
        if (gameworld_obj instanceof Serializable){
            OOS.writeObject(GameWorldObj); // java.io.NotSerializableException
        }
        System.out.printf("SAVED: %s \n", OOS);
        OOS.close();
    } catch (IOException exception){
        System.err.println(String.valueOf(exception));
    } 
    
}   

public static void main(String[] args) {
    new game().Save();
}

我不知道为什么会这样,我在 SO 上搜索并找到了一些告诉你实施的答案 Serializable。我做到了,我仍然收到 NotSerializableException.

为什么会这样?我能做些什么来修复它?

错误信息:

java.io.NotSerializableException: source.library.level.Tiles
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1197)
    at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1582)
    at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1539)
    at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1448)
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1191)
    at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
    at source.library.level.game.Save(game.java:33)
    at source.library.level.game.main(game.java:47)

整个对象图需要是可序列化的,如果至少有一个字段没有实现 Serializable 接口,您将在尝试序列化此 class 的实例时遇到异常.

引自documentation

When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.

原始类型和 JDK 中的大多数 data-types built-in 都是可序列化的。

您可能 运行 遇到麻烦 只有 这些类型:

  • Object 没有实现 Serializable,因此 Object 类型字段不允许出现在 class 中,这意味着可序列化。
  • Optional 以及 OptionalIntOptionalLongOptianalDouble 不可序列化,因为可选类型是作为有限机制引入的 对于 return 类型 并且不打算用作字段。
  • 用作可序列化字段的自定义类型 class 必须是可序列化的。 Tiles class 必须实现 Serializable 并且如果 Tiles 中有一些自定义字段类型,它们也必须是可序列化的。

如果您不希望某个特定字段被序列化,您可以将其标记为transient。瞬态字段以及 static 字段在序列化过程中被忽略。

因此,如果您将字段 tileGrouploadingTiles 设为 transient,则 Tiles class 将不需要实现 Serializable 因为这些属性将从序列化版本中排除。作为反序列化后的结果,它们将被初始化为 null.

一般来说,序列化是用来临时data-storage或者传输数据的。为确保从内存中检索到的对象与 .class 文件兼容,最好定义 static final long serialVersionUID 字段,该字段表示当前版本class.

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

此外,您应该知道序列化有一些严重的draw-backs(看看上面提供的link)。

旁注:class-names通常是单数名词,例如StudentEmployeeTile,因为它们的实例旨在表示单个对象。