【问题标题】:Java Serialization for Extended Class扩展类的 Java 序列化
【发布时间】:2013-08-24 10:49:30
【问题描述】:

在java序列化类Mp3player扩展ElectronicDevice在这段代码中实现了Serializable超类electronicdevice没有实现可序列化。这里的超类也正在序列化。我的理解是超类也因为扩展而被序列化。让我知道我的理解是否正确。

 import java.io.*;
 class ElectronicDevice { 
      ElectronicDevice() 
      {
           System.out.print("ed "); 
      }
  }
 class Mp3player extends ElectronicDevice implements Serializable {
       Mp3player() 
       { 
          System.out.print("mp "); 
       }
 }
class MiniPlayer extends Mp3player {
     MiniPlayer()
     { 
         System.out.print("mini "); 
     }
     public static void main(String[] args) {
          MiniPlayer m = new MiniPlayer();
          try {
                 FileOutputStream fos = new FileOutputStream("dev.txt");
             ObjectOutputStream os = new ObjectOutputStream(fos);
                 os.writeObject(m); os.close();

                 FileInputStream fis = new FileInputStream("dev.txt");
                 ObjectInputStream is = new ObjectInputStream(fis);
                 MiniPlayer m2 = (MiniPlayer) is.readObject(); 
                 is.close();
                 System.out.println();
          } catch (Exception x) {
                System.out.print("x "); 
          }
     }
  }

【问题讨论】:

  • 代码试图准确显示什么?你不明白它的作用是什么?
  • java 序列化机制只关注实现Serializable 的类的实例,因此在您的情况下,从ElectronicDevice 继承的字段(如果有)默认情况下不会被序列化/反序列化,请参阅this回答。
  • 在上面的代码中,电子设备没有实现可序列化的接口,但结果(反序列化后)“ed”也出现在输出中。

标签: java


【解决方案1】:

没有。在序列化的过程中只有Seri​​alizable对象的字段被写出和恢复。

根据javadocs

在反序列化期间,不可序列化类的字段将使用该类的公共或受保护的无参数构造函数进行初始化。

可序列化子类的字段将从流中恢复。

请查看此示例
这里ElectronicDevice不是Serializable,而Mp3player Serializable。观察序列化过程中尊重类行为的字段。

import java.io.*;
class ElectronicDevice  { 
  public int i = 0;
  protected ElectronicDevice() 
  {
       System.out.println("ed "); 
  }
}
class Mp3player extends ElectronicDevice implements Serializable {
   int j =0;
   Mp3player() 
   { 
       System.out.println("mp "); 
   }
}
class MiniPlayer extends Mp3player {
  MiniPlayer()
  { 
      System.out.println("mini "); 
  }
 public static void main(String[] args) {
      MiniPlayer m = new MiniPlayer();
      m.i = 30;
      m.j = 40;
      try {
             System.out.println("i value before serialization: "+m.i);//prints 30
             System.out.println("i value before serialization: "+m.j);//prints 40
             FileOutputStream fos = new FileOutputStream("dev.txt");
             ObjectOutputStream os = new ObjectOutputStream(fos);
             os.writeObject(m); os.close();

             FileInputStream fis = new FileInputStream("dev.txt");
             ObjectInputStream is = new ObjectInputStream(fis);
             MiniPlayer m2 = (MiniPlayer) is.readObject(); 
             is.close();
             System.out.println("i value after serialization: "+m2.i);//prints o
             System.out.println("j value after serialization: "+m2.j);//prints 40
             System.out.println();
        } catch (Exception x) {
            x.printStackTrace();
            System.out.print("x "); 
       }
   }
 }

【讨论】:

    【解决方案2】:

    由于超类没有实现超类的可序列化内容,因此不会被序列化。只有子类的内容会被序列化。当你反序列化时,超类的默认构造函数将被执行,并且超类的字段被初始化,就像你调用了默认构造函数一样。

    下面的例子说明了这一点。

    public class SerializationTest {
    
        public static class Base {
            private String name;
    
            public Base() {
                this.name = "johnDow";
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
        }
    
        public static class Sub extends Base implements Serializable {
            private static final long serialVersionUID = 1L;
            private String age;
    
            public String getAge() {
                return age;
            }
    
            public void setAge(String age) {
                this.age = age;
            }
        }
    
        public static void main(String[] args) throws Exception {
            ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteArrayOS);
            Sub s = new Sub();
            s.setName("name");
            s.setAge("10");
            out.writeObject(s);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteArrayOS.toByteArray()));
            Sub d = (Sub) ois.readObject();
            System.out.println(d.getName() + "-" + d.getAge());
        }
    }
    

    打印出来的是

    johnDow-10
    

    【讨论】:

      【解决方案3】:

      这是超类序列化的规则:

      如果你是一个可序列化的类,但你的超类不是 可序列化,然后是您从中继承的任何实例变量 超类将被重置为它们在 对象的原始构造。这是因为 不可序列化的类构造函数将运行。

      因此,如果您向 ElectronicDevice 添加一些实例变量,请注意超类的状态不会被序列化。 (除非超类实现 Serializable)

      【讨论】:

        【解决方案4】:

        我的理解是超类也被序列化,因为 extends。让我知道我的理解是否正确。

        简短的回答是

        在java中,每个类都是Object的子类。 Object 本身是否实现了Serializable

        【讨论】:

          【解决方案5】:

          为了允许序列化不可序列化类的子类型,子类型可能会负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态”

          参考 - http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

          【讨论】:

            猜你喜欢
            • 2015-12-21
            • 2012-04-23
            • 1970-01-01
            • 1970-01-01
            • 2012-01-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多