【问题标题】:java.io.NotSerializableException even tho the class implements Serializablejava.io.NotSerializableException 即使类实现了 Serializable
【发布时间】:2021-07-23 12:19:32
【问题描述】:

我正在构建一个 music.player,并将我的音乐库存储在 HashMap 中。用户应能够添加和删除歌曲。我想在程序重新启动时保存这个 HashMap。 但是我是否遇到过这个警告:

Exception in thread "main" java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: musicplayer.Song

研究表明我必须在我的 Song 类中实现 Serializable 接口。我做了,但仍然有这个警告。 我的歌曲课:

package musicplayer;
//Song-Klasse, speichert alle Attribute und Methoden eines Songs. Funktioniert soweit
import java.io.File;
import java.io.IOException;
import java.io.Serializable;

public class Song implements Serializable {
    private static final long serialVersionUID = 4390482518182625971L;
    //Attribute
    File file;
    Clip clip;
    String string;
    //...

MusicDatan - 类

package musicplayer;


public class MusicDaten implements Serializable {
    
    private static Map<String,Song> all; //= new HashMap<String,Song>();
    private File file = new File("C://Users//ThinkPad T450s//git//testproject//musicplayer//SongInfo.ser");
    
// ...

    public MusicDaten() throws ClassNotFoundException, IOException {
        this.setSavedSongs();
    }
    
    
    public void setSavedSongs() throws IOException, ClassNotFoundException  { //initialisziert HashMap mit den gespeicherten Songs
        FileInputStream fileIn = new FileInputStream(file);
        ObjectInputStream in = new ObjectInputStream(fileIn);
        all = (HashMap<String,Song>) in.readObject();
        in.close();
        fileIn.close();
    }
    public void save() throws IOException {   //Speicher HashMap
        FileOutputStream fileOut = new FileOutputStream(file);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(all);
        out.close();
        fileOut.close();
        System.out.println("Songinfo saved");
    }

感谢您的帮助。 (在不太清楚之前我已经编辑过这个问题)

【问题讨论】:

  • 到底发生了什么?为什么是allstatic
  • 究竟说错了什么 - 不要让我们猜测。 MusicPlayerGUI 是什么?
  • SongInfo.ser 不存在。
  • 您在寻找\musicplayer\SongInfo.ser 文件的绝对路径是什么?
  • 我不知道如何在这里输入图片,所以我只输入我在 SongInfo.ser 中单击属性时看到的内容。路径:/musicplayer/SongInfo.ser;位置:C:\Users\ThinkPad T450s\git\musicplayer\musicplayer\SongInfo.ser

标签: java eclipse serialization deserialization java-13


【解决方案1】:

实现Serializable 是不够的。

如果您尝试序列化一个对象,它的所有非瞬态属性也会被序列化。如果这些属性中的任何一个不是Serializable,它将不起作用。

在您的情况下,Song 包含File 类型的属性,而File 不可序列化。使用Clip,您也有同样的问题。

为了解决这个问题,您可以进行自定义序列化。

查看the docs of Serializable,你可以找到这个:

在序列化和反序列化过程中需要特殊处理的类必须实现具有这些确切签名的特殊方法:

 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;
 private void readObjectNoData()
       throws ObjectStreamException;

writeObject 方法负责为其特定类写入对象的状态,以便相应的 readObject 方法可以恢复它。可以通过调用 out.defaultWriteObject 来调用保存 Object 字段的默认机制。该方法不需要关注属于其超类或子类的状态。通过使用 writeObject 方法或使用 DataOutput 支持的原始数据类型的方法将各个字段写入 ObjectOutputStream 来保存状态。

readObject 方法负责从流中读取并恢复类字段。它可以调用 in.defaultReadObject 来调用恢复对象的非静态和非瞬态字段的默认机制。

这意味着您可以创建方法 writeObjectreadObject 来指定如何(反)序列化对象。

如果要保留支持序列化的属性的默认(反)序列化,可以将所有不支持序列化的字段标记为transient,并在writeObject/readObject方法中调用out.defaultWriteObject/in.defaultReadObject .

标记属性transient 意味着序列化忽略它。然后,您可以使用您的自定义逻辑。


请注意,序列化会带来一些问题,您可能不想使用它。

一方面,如果您反序列化不受信任的数据,可能会导致严重的拒绝服务甚至远程代码执行漏洞。 the docs of Serializable 中也提到了这一点:

警告:不可信数据的反序列化本质上是危险的,应该避免。应根据Secure Coding Guidelines for Java SE 的“序列化和反序列化”部分仔细验证不受信任的数据。 Serialization Filtering 描述了串行过滤器防御性使用的最佳实践。

序列化的另一个问题是,它将您的应用程序绑定到固定格式,如果您在最初创建应用程序时没有仔细考虑,则在更新应用程序时很难与旧的序列化数据兼容。

有关这方面的更多信息,您可能需要考虑阅读本书Effective Java

【讨论】:

    猜你喜欢
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    • 2011-05-28
    • 2018-01-08
    • 1970-01-01
    • 2018-04-29
    相关资源
    最近更新 更多