我在一篇文章中经历了序列化和可外部化的概念,我发现了这个......” Java 中的内部类无法实现可外部化接口,因为 Java 中内部类的所有构造函数都将始终接受封闭的实例class 作为前置参数,因此内部类不能有无参数构造函数。内部类可以通过仅实现 Serializable 接口来实现对象序列化。 "
请告知以上行的含义。
我在一篇文章中经历了序列化和可外部化的概念,我发现了这个......” Java 中的内部类无法实现可外部化接口,因为 Java 中内部类的所有构造函数都将始终接受封闭的实例class 作为前置参数,因此内部类不能有无参数构造函数。内部类可以通过仅实现 Serializable 接口来实现对象序列化。 "
请告知以上行的含义。
实现 Externalizable 接口的类的规则之一是:
“该类必须有一个公共的无参数构造函数”
当您创建包含内部类的类并对其进行编译时,javac
本质上会为内部类创建一个参数构造函数,其中包含对内部类文件中封闭类的引用.class
,无论您是否在内部类中创建了非参数构造函数。例如考虑下面给出的代码:
import java.io.*;
class ExternalizationDemo
{
public ExternalizationDemo(){System.out.println("Calling external");}
class MyClass implements Externalizable
{
int i = 90;
public MyClass()
{
System.out.println("MyClass Constructor");
i = 299;
}
public void writeExternal(ObjectOutput out)throws IOException
{
System.out.println("Write external of MyClass");
}
public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException
{
System.out.println("Read external of MyClass");
}
}
public static void main(String[] args) throws Exception
{
ExternalizationDemo demo = new ExternalizationDemo();
ExternalizationDemo.MyClass mc = demo.new MyClass();
ObjectOutputStream ous = new ObjectOutputStream(new FileOutputStream("Inner.ser"));
ous.writeObject(mc);
ous.close();
System.out.println("Write successfull");
ObjectInputStream oins = new ObjectInputStream(new FileInputStream("Inner.ser"));
mc = (ExternalizationDemo.MyClass)oins.readObject();//throws java.io.InvalidClassException at this line
System.out.println("Read the object successfully");
}
}
对于上面的代码,javac
创建ExternalizationDemo$MyClass.class
来表示内部类.class
文件。在使用反汇编代码时,javap
我们得到以下指令集:
Compiled from "ExternalizationDemo.java"
class ExternalizationDemo$MyClass extends java.lang.Object implements java.io.Ex
ternalizable{
int i;
final ExternalizationDemo this$0;
public ExternalizationDemo$MyClass(ExternalizationDemo);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LExternalizationDemo;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: aload_0
10: bipush 90
12: putfield #3; //Field i:I
15: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #5; //String MyClass Constructor
20: invokevirtual #6; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
23: aload_0
24: sipush 299
27: putfield #3; //Field i:I
30: return
public void writeExternal(java.io.ObjectOutput) throws java.io.IOException;
Code:
0: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #7; //String Write external of MyClass
5: invokevirtual #6; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
8: return
public void readExternal(java.io.ObjectInput) throws java.io.IOException, java
.lang.ClassNotFoundException;
Code:
0: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #8; //String Read external of MyClass
5: invokevirtual #6; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
8: return
}
如上所示,在第 1 行。8 它包含一个作为参数public ExternalizationDemo$MyClass(ExternalizationDemo);
的构造函数。ExternalizationDemo
它没有包含内部类的无参数构造函数。因此,在尝试将对象转换为ExternalizationDemo$MyClass
at 行时读取内部类的对象后mc = (ExternalizationDemo.MyClass)oins.readObject();
, JIT
找不到嵌套类的非参数构造函数。因此,在抛出以下异常后,对象的读取被中止:
Exception in thread "main" java.io.InvalidClassException: ExternalizationDemo$MyClass; ExternalizationDemo$MyClass; no valid constructor
我希望这能澄清为什么内部类不能实现Externalizable
接口。
内部类构造函数有一个隐式的第一个参数 - 对其封闭类的引用,它是不可见的,它是由 javac 添加的。如果你反编译一个内部类字节码,你可以看到它。因此,Externalizable 所需的内部类中不能有无参数构造函数。不会有编译错误。您甚至可以使用 writeObject 编写 Externalizable 内部类的实例。但是,一旦您尝试使用 readObject 阅读它,您就会得到类似
java.io.InvalidClassException: Test1$Test2; no valid constructor