0

当试图保存我的类 Click 的数组列表时,我收到此错误:java.io.NotSerializableException:javax.swing.text.DefaultHighlighter$LayeredHighlightInfo 在这行代码:os.writeObject(saveList);。即使我让我的 Click 类实现了可序列化。有谁知道这是什么原因?

这是我的保存方法:

public static void saveArray(ArrayList<Click> saveList) {
        JFileChooser c = new JFileChooser();
        c.showSaveDialog(new JFrame());
        File f = c.getSelectedFile();
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
                                f.getAbsolutePath()));
            os.writeObject(saveList);
        } catch (IOException e1) {
        e1.printStackTrace();
    }
}

这是我的 Click 课程:

public static class Click implements Serializable {
    JTextField xClickField;
    JTextField yClickField;
    JTextField clickIntervalField;
    JTextField repeatTimesField;
    boolean isLeft;
    Integer clickX;
    Integer clickY;
    Integer clickInterval;
    Integer clickTimes;

    public Click(boolean left){
        xClickField = new JTextField();
        yClickField = new JTextField();
        clickIntervalField = new JTextField();
        repeatTimesField = new JTextField();
        clickX = 0;
        clickY = 0;
        clickInterval = 0;
        clickTimes = 0;
        isLeft = left;
        addToJPanel();
    }

    public void addToJPanel() {
        xClickField.setText(clickX.toString());
        yClickField.setText(clickY.toString());
        clickIntervalField.setText(clickInterval.toString());
        repeatTimesField.setText(clickTimes.toString());
        panel.add(xClickField);
        panel.add(yClickField);
        panel.add(clickIntervalField);
        panel.add(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }

    public void removeFromJPanel() {
        panel.remove(xClickField);
        panel.remove(yClickField);
        panel.remove(clickIntervalField);
        panel.remove(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }
}

顺便说一句,我从 Click 类中取出了一大块代码。因此,如果您认为错误可能出在代码的那部分,我很乐意将其添加进去。

提前致谢!

4

4 回答 4

2

实现 Serializable 不足以使对象可序列化。例如,一个 Socket 是不可序列化的:序列化一个套接字是没有意义的。因此,如果您有一个Foo具有类型字段Socket并实现的类Serializable,您打算如何序列化Foo实例。它行不通。可序列化对象 msut 的所有字段也可以递归地序列化。

而且,正如 Hovercraft 在他的评论中所说,您应该序列化数据,而不是摆动组件。

于 2012-06-30T17:08:50.383 回答
2

您正在序列化 JTextFields 和其他 Swing 组件,这是浪费时间和资源并且完全没有必要。您应该序列化 GUI 的状态,即类字段保存的数据。如果您了解 MVC,则应该序列化模型,而不是视图。如果您不了解 MVC,请使用 Google 搜索或阅读本文并学习关键概念,因为它们是创建任何语言的 GUI 程序的关键。

另外,为了我的钱,我会使用 JAXB 或其他一些基于 XML 的工具来序列化您的数据,因为它以文本格式保存,因此在阅读时可以理解。

将 GUI 与模型分离并使用属性更改侦听器来侦听和响应属性更改的示例:

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;

public class SimpleClickEg {
   private static void createAndShowGui() {
      SimpleClickPanel clickPanel = new SimpleClickPanel();

      JFrame frame = new JFrame("SimpleClickEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(clickPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class SimpleClickPanel extends JPanel {
   private static final int PREF_WIDTH = 800;
   private static final int PREF_HIEGHT = 600;
   private JTextField clickCountField = new JTextField(5);
   private JTextField clickXField = new JTextField(5);
   private JTextField clickYField = new JTextField(5);
   private SimpleClick click = new SimpleClick();

   public SimpleClickPanel() {
      add(new JLabel("Click X:"));
      add(clickXField);
      add(new JLabel("Click Y:"));
      add(clickYField);
      add(new JLabel("Click Count:"));
      add(clickCountField);

      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            click.setClickPoint(e.getPoint());
         }
      });

      click.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (SimpleClick.CLICK_COUNT.equals(evt.getPropertyName())) {
               clickCountField.setText(String.valueOf(click.getClickCount()));
            } else if (SimpleClick.CLICK_X.equals(evt.getPropertyName())) {
               clickXField.setText(String.valueOf(click.getClickX()));
            } else if (SimpleClick.CLICK_Y.equals(evt.getPropertyName())) {
               clickYField.setText(String.valueOf(click.getClickY()));
            }
         }
      });
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_WIDTH, PREF_HIEGHT);
   }

   public SimpleClick getClick() {
      return click;
   }
}

class SimpleClick implements Serializable {
   private static final long serialVersionUID = 1L;
   public static final String CLICK_COUNT = "click count";
   public static final String CLICK_X = "click x";
   public static final String CLICK_Y = "click y";

   private int clickCount;
   private int clickX;
   private int clickY;
   private transient SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
         this);

   public int getClickCount() {
      return clickCount;
   }

   public void setClickCount(int clickCount) {
      Integer oldValue = this.clickCount;
      Integer newValue = clickCount;
      this.clickCount = newValue;
      spcSupport.firePropertyChange(CLICK_COUNT, oldValue, newValue);
   }

   public void incrementClickCount() {
      setClickCount(getClickCount() + 1);
   }

   public void setClickPoint(Point p) {
      setClickX(p.x);
      setClickY(p.y);
      incrementClickCount();
   }

   public int getClickX() {
      return clickX;
   }

   public void setClickX(int clickX) {
      Integer oldValue = this.clickX;
      Integer newValue = clickX;
      this.clickX = newValue;
      spcSupport.firePropertyChange(CLICK_X, oldValue, newValue);
   }

   public int getClickY() {
      return clickY;
   }

   public void setClickY(int clickY) {
      Integer oldValue = this.clickY;
      Integer newValue = clickY;
      this.clickY = newValue;
      spcSupport.firePropertyChange(CLICK_Y, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.removePropertyChangeListener(listener);
   }

}
于 2012-06-30T17:13:22.457 回答
1

如您所见,错误清楚地表明javax.swing.text.DefaultHighlighter不可序列化。

现在这个类被 . 内部的组合使用JTextField,它是一个 GUI 组件,并不意味着被序列化。从您的代码看来,您似乎不需要序列化字段本身,因此只需将它们标记为transient即可。

附带说明:将数据与 GUI 分开总是很好的,这样您就可以轻松地序列化数据并了解有关 GUI 的任何内容。通常,这不仅有助于序列化,还有助于保持封装并使用 OOP,因为它应该被使用。

于 2012-06-30T17:08:21.217 回答
1

问题是您的Click类引用了 JTextField 实例,并且这些(可能)引用了一些名为DefaultHighlighter.LayeredHighlightInfo... 的 Swing 类,并且它是不可序列化的。

您可能需要将 4 个JTextField变量声明为transient. 作为一般规则,Java GUI 类(如 Swing 组件)不能有效地序列化。

于 2012-06-30T17:08:52.090 回答