当一个类实现Serializable接口时,为什么会出现java.io.NotSerializableException错误?

5
当我尝试使用stashCon.stash()调用序列化对象时,即使类StashCon实现了Serializable接口,我仍然会收到java.io.NotSerializableException的错误信息。
可能的原因是什么?
public boolean connect(String username,String password) {
    try {
        Openfire.connection.connect();
        Openfire.connection.login(username,password);
        stashCon = new StashCon(Openfire.connection);
        stashCon.stash(); // CALL THAT ATTEMPTS TO SERIALIZE THE OBJECT
    }catch(Exception exc){
        exc.printStackTrace();
        return false;
    }
    return true;
}

以下方法属于 StashCon

public void stash() {
    try {
        FileOutputStream outputStream = new FileOutputStream(new File(Constants.BLAB_CONNECTION_FILE));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(this); // LINE 33
        objectOutputStream.close();
        outputStream.close();
    }catch(Exception exc) {
        exc.printStackTrace();
    } 
}

异常

java.io.NotSerializableException: org.jivesoftware.smack.XMPPConnection
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at blab.StashCon.stash(StashCon.java:33)
at blab.Openfire.connect(Openfire.java:27)
at blab.ext.gui.SignIn$4.run(SignIn.java:214)
at java.lang.Thread.run(Thread.java:619)

你不能序列化连接,这没有意义。 - user207421
@EJP 如果您可以详细说明并将其发布为答案 - Suhail Gupta
2个回答

7

您的对象包含了一些成员变量,这些变量本身并不可序列化(例如org.jivesoftware.smack.XMPPConnection实例)。

如果您真的想要对您的对象进行序列化,您需要对该成员变量进行相应处理。其中一个选项是将该变量声明为transient,这样它就不会被序列化。

但是,在反序列化时,您需要处理这个成员变量(比如重新建立连接)。因此,您可以定义readObject方法,在反序列化时调用该方法。在该方法中,您可以(并且很可能应该)初始化所有瞬态成员变量,以将您的对象设置为良好状态。

这里还有一个讨论序列化的好问题。


该类只有一个成员,即XMPPConnection类的实例,该实例不可序列化。在连接建立后如何重用连接对象?让用户在各种场合重新登录会使应用程序变慢,该怎么办? - Suhail Gupta
1
那么,你为什么要首先将数据序列化到文件中呢?我假设你有一个序列化的充分理由。如果你只需要保持连接,那么将其存储在某个单例实例或静态成员中,你可以在程序运行时访问它。如果你想在程序不运行时保持连接,以便稍后重新连接而无需提示密码,则序列化不是一个好的解决方案。为此,您必须存储用户名和密码,这将危及用户帐户安全。 - Matthias

5

XMPPConnection与宿主机上的物理资源(TCP套接字)紧密耦合,因此无法进行序列化。此外,它还具有与连接到服务器相关联的标识,该标识不可复制,因为完整的JID只能连接到同一服务器一次,第二个连接将强制断开另一个连接。

连接不应放入会话中,您必须在该范围之外管理它。


当我需要从另一个类重用connection对象时,该怎么办?重新连接会在各种情况下使应用程序变慢。 - Suhail Gupta
1
在同一个JVM中传递连接对象。不需要也不可能进行序列化。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接