【问题标题】:JAVA: Class Won't SerializeJAVA:类不会序列化
【发布时间】:2013-08-03 06:31:13
【问题描述】:

我一直在编写一个程序来了解更多关于 JAVA 的信息,而且我几乎完成了。自从我使用序列化以来已经有一段时间了,即使在复习之后,我仍然遗漏了一些东西。我正在尝试将此类保存到文件中,但它抛出了 NotSerialzableException。这个类,MonetaryField,包含非原始类型 SingleField,它是序列化的,可以保存到磁盘。它还包含以下内容:

public class MonetaryField extends JPanel implements Serializable {

    private static final long serialVersionUID = 1L;
    public JLabel label;
    public SingleField gold;
    public SingleField silver;
    public SingleField copper;

    public MonetaryField() {

    }

    public MonetaryField(String s, boolean editable, boolean border) {
            label = new JLabel(s);
            gold = new SingleField("gold.png", border);
            silver = new SingleField("silver.png", border);
            copper = new SingleField("copper.png", border);
            gold.addKeyListener(keys);
            silver.addKeyListener(keys);
            copper.addKeyListener(keys);

            if(!editable) {
                    gold.setEditable(false);
                    silver.setEditable(false);
                    copper.setEditable(false);
            }
            GroupLayout layout = new GroupLayout(this);             
            this.setLayout(layout);
            layout.setHorizontalGroup(
                  layout.createSequentialGroup()
                      .addComponent(label)
                      .addComponent(gold)
                      .addComponent(silver)
                      .addComponent(copper)
        );
            layout.setVerticalGroup(
                  layout.createSequentialGroup()
                      .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                       .addComponent(label)
                       .addComponent(gold)
                       .addComponent(silver)
                       .addComponent(copper)
                    ));
    }

    public void setAmount(int g, int s, int c) {
            gold.setValue(g);
            silver.setValue(s);
            copper.setValue(c);
    }

    public void setAmount(String g, String s, String c) {
            gold.setValue(Integer.parseInt(g.replaceAll(",", "")));
            silver.setValue(Integer.parseInt(s.replaceAll(",", "")));
            copper.setValue(Integer.parseInt(c.replaceAll(",", "")));
    }

    public void setAmount(int amount) {
            gold.setValue(Math.floor(amount / 10000));
            silver.setValue(((amount % 10000) - (amount % 100)) / 100);
            copper.setValue(amount % 100);
    }

    public boolean sizeFits(Object field) {
            SingleField s_field = (SingleField) field;
            int max_chars = 4;
            boolean g = s_field.getText().length() < max_chars;
            if(!g) {
                    return false;
            }
            return true;
    }

    KeyListener keys = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
                    if(!Character.isDigit(e.getKeyChar()) || sizeFits(e.getSource()) == false) {
                            e.consume();
                    }
            }

            @Override
            public void keyReleased(KeyEvent e) {    }

            @Override
            public void keyPressed(KeyEvent e) {    }
    };

    public double getAmount() {
            double d = 0.0;
            d += Double.parseDouble(gold.getText());
            d += Double.parseDouble(silver.getText())/100;
            d += Double.parseDouble(copper.getText())/10000;
            return d;
    }
}

最后,这就是我所知道的:非原始类型 SingleField 不是问题,因为它已序列化并成功保存到磁盘。当我在将其保存为数据的类中查询“e.getCause()”时,它说“null”。当我让它返回“e.getMessage”时,它把它归咎于“javax.swing.GroupLayout”。删除 GroupLayout 后,“e.getMessage()”刚刚返回“omnitool.MonetaryField$1”。 Omnitool 是主要的软件包。这就是我离开的地方。我刚刚尝试为你们打印堆栈跟踪(e.getStackTrace().toString),但它告诉我的只是“[Ljava.lang.StackTraceElement;@6ab7501b”......如果有人能解释这意味着什么。另外,我已经对序列化进行了几个小时的研究,但是如果有人有任何好的材料可以分享,那就太好了!

【问题讨论】:

    标签: java notserializableexception


    【解决方案1】:

    要打印出堆栈跟踪,我建议您使用

    e.printStackTrace();
    

    看来您有一个名为keys 的非transient 字段,它是名为omnitool.MonetaryField$1 的匿名内部类,它不是可序列化的,因此不会序列化。您可以将其设为瞬态,但您需要通过定义 readObject 方法在反序列化时重新创建

    http://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html你可以定义一个

    private void readObject(java.io.ObjectInputStream stream)
         throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        // re-initialise transient fields.
    }
    

    我建议您避免将 GUI 组件与数据传输对象混淆。如果您拥有包含纯数据且易于序列化的类以及可可视化该数据的单独 GUI 组件,那么您的生活将会轻松得多。


    我刚刚尝试为你们打印堆栈跟踪 (e.getStackTrace().toString),但它告诉我的只是“[Ljava.lang.StackTraceElement;@6ab7501b”...如果有人能解释那是什么意思。

    这意味着 Java 的 array.toString 已损坏,当您尝试打印普通数组时,它使用 Object.toString() 来打印类,而 System.identHashCode() 很少有用。您需要一个辅助函数,如 Throwable.printStackTrace() 或 Arrays.toString(array) 或自己打印每个元素以查看它。

    【讨论】:

    • 砰!先生,你成功了!幸运的是,我根本不需要它来重新创建我的数据。另一方面,如果这是正常的,它们对我来说都是一样的。非常感谢!
    • 我不知道你所说的“他们都为我打印相同的内容”是什么意思
    • 对不起,我在答案较短时输入了该内容。我的意思是“e.getStackTrace”及其“toString”方法。老实说,我从不使用“toString()”,但它是试图让不同的东西出现的被遗忘的遗物。
    • toString() 不包括堆栈跟踪。只是课程和信息。堆栈跟踪的计算和输出长度都很昂贵,所以我想他们不希望它默认包含在 toString() 中。
    【解决方案2】:

    问题是您的某些字段无法序列化(因为它们没有实现java.io.Serializable 接口)。

    根据您向我们展示的内容,您应该选择:

    transient KeyListener keys = new KeyListener() {
    

    而不是

    KeyListener keys = new KeyListener() {
    

    此外,我没有看到您课程的源代码:SingleField。如果它没有实现java.io.Serializable 接口,您应该将所有这些字段标记为瞬态(或确保您实现了该接口)。

    【讨论】:

      猜你喜欢
      • 2015-08-04
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多