You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父类非序列化时子类序列化含父类变量遇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;
}

原因分析

问题核心在于非静态内部类的序列化机制:

  1. WindowMalfunction是GreenhouseControls的非静态内部类,这类内部类会隐式持有外部类GreenhouseControls的引用;
  2. 序列化GreenhouseControls对象时,eventList中的WindowMalfunction实例会被尝试序列化,但父类Event未实现Serializable接口;
  3. 即使外部类实现了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 19:05:23