程序如下
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class Test { public static void main(String[] args) throws Exception {
Banana2 b = new Banana2();
File file = new File("d:/test.txt");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
oos.writeObject(b);
oos.close();
ois.readObject();
ois.close();
System.out.println( " restored " + b.size + " " );
}
}class Food {
Food() {
System.out.print(" 1 ");
}
}class Fruit extends Food implements Serializable {
private static final long serialVersionUID = 2387924016119347282L; Fruit() {
System.out.print(" 2 ");
}
}class Banana2 extends Fruit {
private static final long serialVersionUID = 7689053551729518274L;
int size = 42;
}运行结果: 1  2  1  restored 42 
谁解释哈1 2后面那个1怎么出的啊,我百思不得其解。

解决方案 »

  1.   

    因为Food不可以序列化,而读出来的是一个Banana2,Banana2是可以序列化的,Fruit也是可以序列化的,所以需要构造一个初始的Food。
      

  2.   

    查一下API,ObjectInputStream 里面有说明,对序列化和反序列化的
      

  3.   

    解序列会调用一个隐藏的构造器,这个构造器和一般显式的一样,会首先调用super()。这就是为什么会打印出Food里面的1;没有再打印出显式构造器中的2.
      

  4.   

    在java 序列化中 允许非序列化类的子类型序列化,子类型可以假定负责保存和恢复父类型的公有的、保护的和(如果可访问)包的域的状态。只要该类(扩展)有一个无参构造子,可初始化它的状态,那么子类型就可承担上述职责。也就是说Food类不可序列化 但Banana2 可以序列化 Banana2 是Food的子类 它负责保存和恢复Food类相关的域的状态 当Banana2类反序列化得时候 会调用Food的构造函数 实例化Food类 这时就会输出值 1 ,而对Fruit 类而言虽然它也是Banana2的父类 但是它是可以序列化的 在反序列化的时候 它的对象其实本来就是存在的 只需要反序列化恢复成对象就可以了 不需要再调用构造函数实例化 楼主可以试试 把Food类改成可以序列化 的 而它的两级子类Fruit 和 Banana2不再明文实现Serializable接口 结果按上面所说 就应该是 1  2  restored 42  如果把Food 和 Fruit类改成不可序列化 那么结果就是 1  2  1  2  restored 42 
      

  5.   


    反序列化出来的,只会有一个Banana2实例,不会有Fruit实例出现,更不会有Food的实例出现。请注意,调用父类的构造函数(即super()),不会创建一个父类的实例。在jvm指令集中,super()对应的指令是invokespecial, 创建实例只有一个指令,那就是new。
      

  6.   

    我对你的代码加了点料,把Food类改成如下所示(其它类不变):class Food{
      Food() {
        System.out.print(" 1 ");
        new Exception().printStackTrace();
      }
    }
    运行后打印出方法栈如下:
     java.lang.Exception
            at Food.<init>(Test.java:26)
            at sun.reflect.GeneratedSerializationConstructorAccessor2.newInstance(Unknown Source)
            at java.lang.reflect.Constructor.newInstance(Unknown Source)
            at java.io.ObjectStreamClass.newInstance(Unknown Source)
            at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
            at java.io.ObjectInputStream.readObject0(Unknown Source)
            at java.io.ObjectInputStream.readObject(Unknown Source)
            at Test.main(Test.java:17)
    =================================================================================
    接下来保持Food类如上不变,将实现Serializable接口的类改成Banana2,运行,打印如下:java.lang.Exception
            at Food.<init>(Test.java:26)
            at Fruit.<init>(Test.java:33)
            at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Uknown Source)
            at java.lang.reflect.Constructor.newInstance(Unknown Source)
            at java.io.ObjectStreamClass.newInstance(Unknown Source)
            at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
            at java.io.ObjectInputStream.readObject0(Unknown Source)
            at java.io.ObjectInputStream.readObject(Unknown Source)
            at Test.main(Test.java:17)
    你可能注意到了两次动态创建的隐藏构造器是不一样的。暂时我也就挖掘到这里
      

  7.   

    个人觉得这种解释比较合理,
    这就是sun的scjp考试的考题,考的都是一些变态题,郁闷啊