父类非序列化时子类序列化含父类变量遇NotSerializableException问题
序列化问题:内部类WindowMalfunction抛出NotSerializableException
问题背景
刚接触序列化技术,目前遇到困境:有父类Controller.java和子类GreenhouseControls.java,需要序列化GreenhouseControls对象,同时保存父类Controller中的实例变量eventList。
序列化操作由GreenhouseControls的内部类抛出自定义ControllerException触发,异常会在main方法中被捕获,程序终止前需保存包含父类字段的GreenhouseControls对象。
尝试两种方案均失败,抛出相同异常:java.io.NotSerializableException: GreenhouseControls$WindowMalfunction:
- 让
Controller实现Serializable接口(父类可序列化则子类自动具备序列化能力); - 让
GreenhouseControls实现Serializable接口,并重写writeObject()和readObject()方法自定义序列化以保存父类字段。
自定义序列化代码如下:
private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeObject(super.eventList); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); Object obj = in.readObject(); List<Event> x = cast(obj); super.eventList = x; }
原因分析
问题核心在于非静态内部类的序列化机制:
WindowMalfunction是GreenhouseControls的非静态内部类,这类内部类会隐式持有外部类GreenhouseControls的引用;- 序列化
GreenhouseControls对象时,eventList中的WindowMalfunction实例会被尝试序列化,但父类Event未实现Serializable接口; - 即使外部类实现了
Serializable,未实现该接口的内部类会因持有外部类引用,触发NotSerializableException。
解决方案
需要从三个层面修正:
1. 让Event类实现Serializable
所有继承自Event的内部类都需要被序列化,因此父类Event必须先实现接口:
import java.io.Serializable; public abstract class Event implements Serializable { private long eventTime; protected final long delayTime; public Event(long delayTime) { this.delayTime = delayTime; start(); } public void start() { // Allows restarting eventTime = System.currentTimeMillis() + delayTime; } public boolean ready() { return System.currentTimeMillis() >= eventTime; } public abstract void action() throws ControllerException; }
2. 处理非静态内部类的序列化
非静态内部类序列化依赖外部类引用,有两种处理方式:
方式一:将内部类改为静态内部类
静态内部类不会持有外部类的隐式引用,修改WindowMalfunction和PowerOut:
public static class WindowMalfunction extends Event { public WindowMalfunction(long delayTime) { super(delayTime); } public void action() throws ControllerException { // 注意:静态内部类无法直接访问外部类非静态成员,需通过外部类实例访问 throw new ControllerException("Window malfunction"); } public String toString() { return "Window malfunction"; } }
方式二:让内部类也实现Serializable
若必须保留非静态内部类,需让内部类同样实现Serializable接口:
public class WindowMalfunction extends Event implements Serializable { public WindowMalfunction(long delayTime) { super(delayTime); } public void action() throws ControllerException { windowok = false; throw new ControllerException("Window malfunction"); } public String toString() { return "Window malfunction"; } }
注意:此方式下外部类GreenhouseControls必须已实现Serializable,否则内部类的外部引用会导致序列化失败。
3. 简化父类字段的序列化(可选)
让Controller直接实现Serializable,无需在子类中重写序列化方法,Java会自动序列化父类的可序列化字段:
import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Controller implements Serializable { protected List<Event> eventList = new ArrayList<Event>(); public void addEvent(Event c) { eventList.add(c); } public void run() throws ControllerException { while (eventList.size() > 0) for (Event e : new ArrayList<Event>(eventList)) if (e.ready()) { System.out.println(e); e.action(); eventList.remove(e); } } public static void shutDown() { } }
完整修改后代码示例
Controller.java
import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Controller implements Serializable { protected List<Event> eventList = new ArrayList<Event>(); public void addEvent(Event c) { eventList.add(c); } public void run() throws ControllerException { while (eventList.size() > 0) for (Event e : new ArrayList<Event>(eventList)) if (e.ready()) { System.out.println(e); e.action(); eventList.remove(e); } } public static void shutDown() { } }
Event.java
import java.io.Serializable; public abstract class Event implements Serializable { private long eventTime; protected final long delayTime; public Event(long delayTime) { this.delayTime = delayTime; start(); } public void start() { eventTime = System.currentTimeMillis() + delayTime; } public boolean ready() { return System.currentTimeMillis() >= eventTime; } public abstract void action() throws ControllerException; }
GreenhouseControls.java(关键修改部分)
public class GreenhouseControls extends Controller implements Serializable { private int errorcode = 0; private boolean windowok = true; private boolean poweron = true; // 修改为静态内部类 public static class WindowMalfunction extends Event { public WindowMalfunction(long delayTime) { super(delayTime); } public void action() throws ControllerException { throw new ControllerException("Window malfunction"); } public String toString() { return "Window malfunction"; } } public static class PowerOut extends Event { public PowerOut(long delayTime) { super(delayTime); } public void action() throws ControllerException { throw new ControllerException("Power out"); } public String toString() { return "Power out"; } } // 其他原有代码保持不变... public static void main(String[] args) { // 原有main方法代码保持不变... } }
内容的提问来源于stack exchange,提问作者ires
相关产品推荐
相关产品推荐

