CodeQL 文档

非序列化类的可序列化内部类

ID: java/non-serializable-inner-class
Kind: problem
Security severity: 
Severity: warning
Precision: medium
Tags:
   - reliability
   - maintainability
   - language-features
Query suites:
   - java-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

实现 Serializable 的非静态嵌套类必须定义在也是可序列化的封闭类中。非静态嵌套类保留对封闭类实例的隐式引用。如果封闭类不可序列化,Java 序列化机制将使用 java.io.NotSerializableException 失败。

建议

要避免导致 NotSerializableException,请执行以下操作之一

  • 将嵌套类声明为 static : 如果嵌套类不使用封闭类的任何非静态字段或方法,最好将其声明为 static。这将删除对封闭类实例的隐式引用,并且还会断开这两个类之间不必要的依赖关系。类似的解决方案是将嵌套类变成独立的顶级类。

  • 使封闭类实现 Serializable : 但是,不建议这样做,因为内部类的实现可能是特定于编译器的,并且序列化内部类会导致跨编译器的不可移植性。Java 序列化规范指出

    强烈建议不要序列化内部类(即非静态成员类),包括局部类和匿名类,原因如下:

示例

在以下示例中,类 WrongSession 无法序列化,否则会引发 NotSerializableException,因为它被封闭在一个非可序列化类中。但是,类 Session 可以序列化,因为它被声明为 static

class NonSerializableServer {

    // BAD: The following class is serializable, but the enclosing class
    // 'NonSerializableServer' is not. Serializing an instance of 'WrongSession' 
    // causes a 'java.io.NotSerializableException'.
    class WrongSession implements Serializable {
        private static final long serialVersionUID = 8970783971992397218L;
        private int id;
        private String user;
        
        WrongSession(int id, String user) { /*...*/ }
    }
    
    public WrongSession getNewSession(String user) {
        return new WrongSession(newId(), user);
    }
}

class Server {

    // GOOD: The following class can be correctly serialized because it is static.
    static class Session implements Serializable {
        private static final long serialVersionUID = 1065454318648105638L;
        private int id;
        private String user;
        
        Session(int id, String user) { /*...*/ }
    }
    
    public Session getNewSession(String user) {
        return new Session(newId(), user);
    }
}

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私