【问题标题】:Java Serialization with an Interface带有接口的 Java 序列化
【发布时间】:2016-04-14 05:21:18
【问题描述】:

我在将对象写入文件和从 Java 文件中读取对象时都遇到了问题。我必须在一个类中为每个类编写一个方法,该类扩展给我们的接口。我现在的代码如下:

package onlineTest;

import java.util.*;
import java.io.*;

public class SystemManager implements Manager, Serializable {

...

private static final long serialVersionUID = 1L;

public void saveManager(Manager manager, String fileName){

    try{
        FileOutputStream fileOut = new FileOutputStream(fileName);
        ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
        objectOut.writeObject(manager);
        objectOut.close();
    }catch(IOException e){
        e.printStackTrace();
    }
}

public Manager restoreManager(String fileName){

    Manager m = null;
    try{
        FileInputStream fileIn = new FileInputStream(fileName);
        ObjectInputStream objectIn = new ObjectInputStream(fileIn);
        m = (Manager) objectIn.readObject();
        objectIn.close();
        fileIn.close();
    }catch(IOException e){
        e.printStackTrace();
        return null;
    }catch(ClassNotFoundException f){
        f.printStackTrace();
        return null;
    }
    return m;

}

}

唯一必须保留的部分是这两个方法的标题,其中的任何内容都可以更改,但我不能更改任何标题。当我尝试运行它时,它给了我一个错误,我在 saveManager 方法中写入 objectOut.writeObject(manager) 但我无法弄清楚我做错了什么。

【问题讨论】:

  • “它给了我一个错误” 错误是什么?是运行时还是编译时?请提供编译错误或堆栈跟踪的全文。
  • 你的班级是否实现了Serializable
  • Manager 是否扩展 Serializable
  • Manager 不扩展 Serializable,但我不相信我可以更改它,所以它确实扩展了 Serializable。对于错误,它给了我一个 NotSerializableException。
  • @jblackman76 在这种情况下,您需要澄清问题。 Manager 是一个接口,如果该接口没有扩展 Serializable,您将不得不求助于一些非常可怕的事情(例如,调用 getClass(),然后使用反射找出您需要保存的所有字段)。

标签: java serialization interface


【解决方案1】:

为了序列化一个类,Java 序列化机制要求该类实现Serializable

如果您的 Manager 类本身没有实现 Serializable 并且不能这样做,那么您可以使用 saveManager 方法进行一些选择,但显然没有一个是最好的:

  • saveManager 方法的签名更改为需要ManagerSerializable 子类,例如SystemManager;但是,这有点限制,因为您可能想要序列化 ​​Manager 的其他实现;
  • saveManager 中添加一个前置条件检查以检查manager instanceof Serializable。这样做的缺点是它是一个运行时异常,实际上与您现在的情况并没有太大区别;
  • 您还可以定义一个通用约束,该约束需要一个类来实现ManagerSerializable

    <M extends Foo & Serializable> void saveManager(M manager, String filename) {
    

    但是,这需要您引用 Manager 的特定子类型才能调用它 - 例如如果您引用了SystemManager,则可以,但如果您引用了值为SystemManagerManager,则不能:

    SystemManager sysMan = ...
    Manager plainMan = sysMan;
    
    saveManager(sysMan, "filename");  // OK!
    saveManager(plainMan, "filename");  // Error, despite sysMan == plainMan.
    

还要注意,类实现Serializable 的事实并不能保证序列化会成功。类存储的所有引用的传递闭包也必须实现Serializable

我提到了另一种解决方案 - 使 Manager 扩展 Serializable - 但这也不一定是正确的做法。由于实现Serializable 的类的负担——它们的引用的传递闭包也必须是Serializable——将这个接口添加到基类会带来沉重的负担。显然,有时这样做是正确的,但正如 Effective Java 2nd Ed 第 74 条所述:

“明智地实施Serializable”。

有一个非常有用的 JVM 标志,用于标识导致序列化失败的特定类:

-Dsun.io.serialization.extendedDebugInfo=true

是的,Java 中的序列化是一团糟。

【讨论】:

  • 我无法更改该方法的任何约束,也无法更改该方法的签名。我尝试添加前置条件检查管理器 instanceof Serializable,但由于某种原因,我仍然收到 NotSerializableException。我还收到了 WriteAbortedException。
  • 正确 - 请注意我所说的关于实现 Serializable 的东西不一定是可序列化的,以及如何获取有关失败的其他信息...
  • 我不确定如何或在何处添加 JVM 标志来识别导致序列化失败的特定类。
  • java 之后和你的主要类名/JAR 之前的某个位置。
  • 对不起,我知道这可能是一个愚蠢的问题,但是你在 java 之后是什么意思?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多