Reputation: 121
I was going through the concept of serilization and externilizable in an article I found this ..."Externalizable interface can't be implemented by Inner Classes in Java as all the constructors of an inner class in Java will always accept the instance of the enclosing class as a prepended parameter and therefore you can't have a no-arg constructor for an inner class. Inner classes can achieve object serialization by only implementing Serializable interface."
Please advise what is mean by the above lines.
Upvotes: 1
Views: 119
Reputation: 13066
One of the rules that the class implementing Externalizable interface is that:
"The class must have a public no-arg constructor"
When you create a class containing an inner class and compile it , javac
inherently creates a parametric constructor for inner class containing the reference to enclosing class in .class
file for inner class, irrespective of whether you have created non-argument constructor within the inner class or not. For example consider the code given below:
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");
}
}
For above code javac
create ExternalizationDemo$MyClass.class
to represent inner class .class
file. On disassembling the code using javap
we get the following set of instructions:
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
}
As seen above , At line no. 8 it contains a constructor public ExternalizationDemo$MyClass(ExternalizationDemo);
having ExternalizationDemo
as parameter. It nowhere includes the parameter-less constructor for the inner class. Hence , after reading the object of inner class when attempt is made to cast the object to ExternalizationDemo$MyClass
at line mc = (ExternalizationDemo.MyClass)oins.readObject();
, JIT
doesn't find the non argument constructor for the nested class . Hence the read of object is aborted after throwing following exception:
Exception in thread "main" java.io.InvalidClassException: ExternalizationDemo$MyClass; ExternalizationDemo$MyClass; no valid constructor
I hope this clarifies Why the inner class can't implement Externalizable
interface.
Upvotes: 2
Reputation: 136062
Inner class constructors have an implicit first parameter - a reference to its enclosing class, it's invisible, it's added by javac. You can see it if you decompile an inner class bytecode. So there can be no no-arg constructor in an inner class which is required by Externalizable. There will be no compile error. You can even write an instance of an Externalizable inner class with writeObject. But as soon as you try to read it with readObject you will get something like
java.io.InvalidClassException: Test1$Test2; no valid constructor
Upvotes: 0