Saral Saxena
Saral Saxena

Reputation: 121

Difference of externilzable in article

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

Answers (2)

Vishal K
Vishal K

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

Evgeniy Dorofeev
Evgeniy Dorofeev

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

Related Questions