MENU

Java杂记(五)坑:内部类 + 序列化

June 20, 2018 • Code

前言:Java 中内部类与序列化同时使用时可能会出现意想不到的结果。

主要内容

给出一个栗子:

public class Out {
    
    class Inner implements Serializable {
        public int a;
    }
    
    public static void main(String[] args) {
        Out out = new Out();
        Out.Inner inner = out.new Inner();
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(
                    new FileOutputStream("/Users/kbrx93/Downloads/Inner.ser"));
            outputStream.writeObject(inner);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上面栗子本质上就是将内部类 Inner 序列化,运行结果如下:

提示 Out 类无法序列化,将 Inner 类对应的 Out$Inner.class 反编译:

jad Out$Inner.class

得到如下结果:

class Out$Inner
    implements Serializable
{
    
    public int a;
    final Out this$0;
    
    Out$Inner()
    {
        this.this$0 = Out.this;
        super();
    }
}    

由上面的结果可知:编译器在内部类中生成了对应外部类的引用,并生成一个构造器来初始化此引用。

这也是为什么内部类可以访问外部类所以成员变量的原因。

从Java的文档我们也可以找到解释:

If the constructor’s declaring class is an inner class in a non-static context, the first argument to the constructor needs to be the enclosing instance; see The Java Language Specification, section 15.9.3

而一个类能被序列化需要具备有两个条件:

  • 实现 Serializable 接口。

  • 类中所有的成员变量都要可序列化,如果变量是类引用,则对应的类须实现 Serializable 接口。

因此上面出错原因也就清楚:外部类 Out 没有实现 Serializable 接口,无法被序列化。

解决方法

  • Out 类实现 Serializable 接口。

  • Inner 类变为静态类,这样编译就不会在类内部自动生成外部类的引用。

同时注意:静态变量是无法被被序列化的。

小结

内部类与序列化同时使用会出现不可预测的结果,如果可以,最好不要使用内部类 + 序列化的组合。

Last Modified: July 5, 2018
Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment