1

我在一篇文章中经历了序列化和可外部化的概念,我发现了这个......” Java 中的内部类无法实现可外部化接口,因为 Java 中内部类的所有构造函数都将始终接受封闭的实例class 作为前置参数,因此内部类不能有无参数构造函数。内部类可以通过仅实现 Serializable 接口来实现对象序列化。 "

请告知以上行的含义。

4

2 回答 2

2

实现 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$MyClassat 行时读取内部类的对象后mc = (ExternalizationDemo.MyClass)oins.readObject();JIT找不到嵌套类的非参数构造函数。因此,在抛出以下异常后,对象的读取被中止:

Exception in thread "main" java.io.InvalidClassException: ExternalizationDemo$MyClass; ExternalizationDemo$MyClass; no valid constructor

我希望这能澄清为什么内部类不能实现Externalizable接口。

于 2013-03-27T12:03:53.577 回答
0

内部类构造函数有一个隐式的第一个参数 - 对其封闭类的引用,它是不可见的,它是由 javac 添加的。如果你反编译一个内部类字节码,你可以看到它。因此,Externalizable 所需的内部类中不能有无参数构造函数。不会有编译错误。您甚至可以使用 writeObject 编写 Externalizable 内部类的实例。但是,一旦您尝试使用 readObject 阅读它,您就会得到类似

 java.io.InvalidClassException: Test1$Test2; no valid constructor
于 2013-03-27T10:55:29.263 回答