所以最近我正在为我们开发一个工具来配置某些应用程序。它不需要真正棒极了,只需要生成一些SQL脚本的基本工具,并创建几个XML文件。在此期间,我使用自己的AbstractTableModel实现创建了一系列JTable对象。在我构建了所有内容之后,并且使用AbstractTableModel(仅使用ObjectStreamWriter写入磁盘)测试保存和加载时,序列化失败。我几乎整天都在弄清楚发生了什么。当我尝试序列化它们时,我会在java.lang.reflect.Constructor上得到一个NotSerializableException。我不知道这是什么,因为我的表模型只包含可序列化的实体,我附加的所有监听器也是可序列化的,父类也是可序列化的。经过大量的挖掘和一些有用的帖子后,我发现当你将一个TableModelListener添加到一个AbstractTableModel实现时,除了你添加的一个监听器之外还添加了另一个监听器,类型为javax.swing.event.TableModelListener,它不是t serializable(参见http://docs.oracle.com/javase/7/docs/api/javax/swing/event/TableModelListener.html的接口,我不知道实现)。 编辑模型不会添加这个非可序列化的监听器,JTable会这样做。我的问题基本上是,为什么这个对象会在内部添加自己的非可序列化对象,从而否定了它实际上实现了Serializable的事实?这是我应该报告的错误吗?
仅供参考我的工作是简单地删除所有侦听器,序列化,然后重新添加侦听器。反序列化时我只需要添加我创建的那个,模型再次创建另一个。
编辑 尝试使用通过调用setValueAt()方法提供的序列化程序类来序列化此模型。
import java.io.Serializable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
public class BlankTableModel extends AbstractTableModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6063143451207205385L;
public BlankTableModel()
{
this.addTableModelListener(new InnerTableModelListener());
}
@Override
public void setValueAt(Object o, int x, int y)
{
this.fireTableChanged(new TableModelEvent(this, x, y));
}
public int getColumnCount() {
// TODO Auto-generated method stub
return 2;
}
public int getRowCount() {
// TODO Auto-generated method stub
return 2;
}
public Object getValueAt(int arg0, int arg1) {
// TODO Auto-generated method stub
return "Test Data";
}
private void save()
{
Serializer.SerializeObject(this);
}
@Override
public boolean isCellEditable(int rowindex, int colindex)
{
return true;
}
private class InnerTableModelListener implements TableModelListener, Serializable
{
@Override
public void tableChanged(TableModelEvent arg0) {
save();
}
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Serializer {
public static void SerializeObject(Serializable object)
{
File out = new File("USE A VALID PATH");
if (!out.exists())
{
try {
out.createNewFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
else
{
out.delete();
try {
out.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try (FileOutputStream fos = new FileOutputStream(out);
ObjectOutputStream oos = new ObjectOutputStream(fos))
{
oos.writeObject(object);
}catch (Exception e)
{
e.printStackTrace();
}
}
}
然后尝试用此
替换save方法private void save()
{
for (TableModelListener l : this.getTableModelListeners())
{
this.removeTableModelListener(l);
}
Serializer.SerializeObject(this);
this.addTableModelListener(new InnerTableModelListener());
}
这是一个简单的gui
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JTable;
public class MainForm extends JFrame {
public static void main(String[] args)
{
MainForm form = new MainForm();
form.show();
}
public MainForm()
{
this.setBounds(100, 100, 600, 600);
BlankTableModel model = new BlankTableModel();
JTable table = new JTable(model);
table.setPreferredSize(new Dimension(500,500));
this.getContentPane().add(table);
}
}
答案 0 :(得分:3)
JTable
,TableModelListener
为TableModel
,Serializable
为TableModel
。您的自定义Serializable
为TableModelListener
。添加另外Serializable
也是TableModel
应该没有区别,如下所示。一些建议:
验证Serializable
中包含的数据结构本身是否为System.out.println(copyObject(data));
。如果这代表bug,则可以仅序列化模型的内部数据结构。例如,
JTable
批判性地检查您在此上下文中使用序列化的选择;另见Effective Java: Chapter 11. Serialization。
附录:我更新了示例以实例化import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
/* @see http://stackoverflow.com/a/19300995/230513 */
public class SerializationTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JTable table = new JTable(new BlankTableModel());
JTable copy = copyObject(table);
copy.setValueAt("New data", 0, 0);
JFrame f = new JFrame("SerializationTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1, 5, 5));
f.add(table, BorderLayout.NORTH);
f.add(copy, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class BlankTableModel extends AbstractTableModel implements Serializable {
private static final long serialVersionUID = 3141592653589793L;
private String data = "Test data";
public BlankTableModel() {
this.addTableModelListener(new InnerTableModelListener());
}
@Override
public void setValueAt(Object o, int row, int col) {
data = o.toString();
this.fireTableCellUpdated(row, col);
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public int getRowCount() {
return 2;
}
@Override
public Object getValueAt(int row, int col) {
return data;
}
private void save() {
BlankTableModel model = copyObject(this);
System.out.println(model.getValueAt(0, 0));
}
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
private class InnerTableModelListener implements TableModelListener, Serializable {
private static final long serialVersionUID = 2718281828459045L;
@Override
public void tableChanged(TableModelEvent e) {
save();
}
}
}
private static <T extends Serializable> T copyObject(final T source) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(source);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(baos.toByteArray()));
final T copy = (T) ois.readObject();
return copy;
} catch (Exception e) {
throw new AssertionError("Error copying: " + source);
}
}
}
,使用序列化克隆表,更新副本并显示两者。
屏幕:
控制台:
New data
SSCCE:
{{1}}