`

序列化中的继承问题

阅读更多


package tigers;

import java.io.*;


public class Tiger3 {
static class Sub extends Super {
private String name;
public Sub(int id, int uid, String name) {
super(id, uid);
this.name = name;
}
public String toString() {
return "Tiger3$Sub:(" + super.toString() + "," + name + ")";
}

private void writeObject(ObjectOutputStream oos) throws IOException {
System.out.println("Sub.writeObject()");
oos.defaultWriteObject();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
System.out.println("Sub.readObject()");
ois.defaultReadObject();
}
}
static class Super implements Serializable {
private int id;
private transient int uid;
public Super(int id, int uid) {
this.id = id;
this.uid = uid;
}
private static final long serialVersionUID = 1L;
private void writeObject(ObjectOutputStream oos) throws IOException {
System.out.println("Super.writeObject()");
oos.defaultWriteObject();
oos.writeInt(uid);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
System.out.println("Super.readObject()");
ois.defaultReadObject();
uid = ois.readInt();
}
public String toString() {
return "Tiger3$Super:(" + id + "," + uid + ")";
}
}
public static void main(String[] args) {
Tiger3.Super sup = new Tiger3.Super(55, 1000);
Tiger3.Sub sub = new Tiger3.Sub(12, 100, "sub");
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Tiger3$Super.tmp"));
oos.writeObject(sup);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Tiger3$Super.tmp"));
sup = (Tiger3.Super) ois.readObject();
System.out.println(sup);
oos = new ObjectOutputStream(new FileOutputStream("Tiger3$Sub.tmp"));
oos.writeObject(sub);
ois = new ObjectInputStream(new FileInputStream("Tiger3$Sub.tmp"));
sub = (Tiger3.Sub) ois.readObject();
System.out.println(sub);
} catch (IOException ioe) {

} catch (ClassNotFoundException cnfe) {

}
}
}

结果:

Super.writerObject()
Super.readObject()
Tiger3$Super:(55,1000)
Super.writerObject()
Sub.writeObject()
Super.readObject()
Sub.readObject()
Tiger3$Sub:(Tiger3$Super:(12,100),sub)

如果将Super和Sub中writeObject()和readObject()的修饰符改成public:

Tiger3$Super:(55,0)
Tiger3$Sub:(Tiger3$Super:(12,0),sub)


Tiger3$Super:(55,0)
Tiger3$Sub:(Tiger3$Super:(12,0),sub)


结论:

一、如果Super类包含需要序列化的primitive类型变量,应该实现writeObject()和readObject()方法,并在里面分别调用ObjectOutputStream.defaultWriteObject()和ObjectInputStream.defaultReadObject()方法。

二、writeObject()和readObject()的修饰符、返回类型、参数必须符合规定,即必须是如下格式:

private void writeObject(ObjectOutputStream o) throws...;

private void readObject(ObjectInputStream o) throws...;

否则这两个方法将不会被调用。

三、如果父类实现了Serializable接口,子类将自动得到可序列化特性。并且序列化子类时,父类的writeObject()和readObject()将得到调用。换言之,在序列化子类之前,父类将会自动被序列化。

/*
* Created on 2005-2-7
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package tigers;

import java.io.*;

/**
* @author bitan
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Tiger4 {
static class Super {
private String name;
public Super(String name) {
this.name = name;
}
public String toString() {
return "Tiger4$Super:(" + name + ")";
}
}
static class Sub extends Super implements Serializable {
private String name;
Sub (String superName, String name) {
super(superName);
this.name = name;
}
public String toString() {
return "Tiger4$Sub:("+ super.toString() + "," + name + ")";
}
}
public static void main(String[] args) {
Sub sub = new Sub("super","sub");
try {
System.out.println("序列化之前:" + sub);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Tiger4$Sub.tmp"));
oos.writeObject(sub);
System.out.println("序列化之后:" + sub);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Tiger4$Sub.tmp"));
sub = (Sub) ois.readObject();
System.out.println("反序列化之后:" + sub);
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
}

结果:

序列化之前:Tiger4$Sub:(Tiger4$Super:(super),sub)
序列化之后:Tiger4$Sub:(Tiger4$Super:(super),sub)

java.io.InvalidClassException: tigers.Tiger4$Sub; no valid constructor
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:428)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:268)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1029)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:291)
at tigers.Tiger4.main(Tiger4.java:41)

给Super加上无参数构造函数

public Super() {

this.name = "default";

}

后:

序列化之前:Tiger4$Sub:(Tiger4$Super:(super),sub)
序列化之后:Tiger4$Sub:(Tiger4$Super:(super),sub)
反序列化之后:Tiger4$Sub:(Tiger4$Super:(default),sub)

现在,给Super的name字段加上Setter和Getter方法:

public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}

并且给Sub加上writeObject()和readObject()方法:

private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(super.getName());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
super.setName((String) ois.readObject());
}

结果:

序列化之前:Tiger4$Sub:(Tiger4$Super:(super),sub)
序列化之后:Tiger4$Sub:(Tiger4$Super:(super),sub)
反序列化之后:Tiger4$Sub:(Tiger4$Super:(super),sub)

结论:

一、当父类没有实现Serializable接口的前提下,序列化子类时父类将不会被自动序列化。而反序列化子类时,父类的无参数构造方法将会被调用。

二、如果想在序列化子类的同时也自动序列化父类中的字段,必须在子类的writeObject()和readObject()中相应实现。



分享到:
评论

相关推荐

    java 对象的序列化与反序列化

    6. **安全性问题**:序列化可能导致安全漏洞,因为恶意用户可以通过反序列化执行任意代码。因此,谨慎处理来自不可信源的序列化数据,并考虑使用安全的反序列化库或自定义序列化逻辑。 接下来是反序列化,它是序列...

    hashtable序列化与反序列化

    `HashTable`继承自`Dictionary`类,并实现了`Serializable`接口,因此它支持序列化操作。 要序列化一个`HashTable`对象,我们需要执行以下步骤: 1. 确保`HashTable`类或包含它的类实现了`Serializable`接口。例如...

    C#对象序列化与反序列化

    - **反序列化的使用总结**:反序列化时需要注意类型兼容性和安全性问题。 #### 6. 自定义序列化(仅适用于二进制与SOAP) ##### (1) 自定义序列化的实现方式 - 实现`ISerializable`接口:允许开发者控制序列化过程...

    MFC序列化资料文档 序列化资料

    在Microsoft Foundation Classes (MFC)库中,序列化是一个关键概念,它允许对象的状态被保存到文件或数据库中,然后在以后的时间点恢复。序列化是面向对象编程中的一种技术,使得程序可以将数据持久化,即从内存中的...

    C#对象序列化反序列化保存与读取和对象直接保存与读取

    对象序列化和反序列化不仅简化了对象的持久化过程,而且可以处理更复杂的数据结构,包括继承、接口、枚举等。此外,它们还提供了版本兼容性,允许在不同版本的代码之间序列化和反序列化对象。 在Windows Forms应用...

    C++CArchive序列化存储

    在C++类中,通过继承`CObject`类或者包含`DECLARE_SERIAL`和`IMPLEMENT_SERIAL`宏来启用序列化。`DECLARE_SERIAL`宏声明类为可序列化的,`IMPLEMENT_SERIAL`宏则实现具体的序列化逻辑。在类中,重载`Serialize`函数...

    C/C++结构体序列化配置模板化

    另外,考虑到配置文件可能需要保存在特定格式(如XML、JSON或YAML)中,可以设计一个接口,让不同格式的序列化器继承自该接口,然后通过模板参数选择合适的实现。这样可以轻松地在不同格式之间切换,而无需大量修改...

    序列化与反序列化示例

    在.NET框架中,序列化和反序列化是两个重要的概念,它们主要用来处理对象的状态转换。...在项目中,你可能会遇到更多复杂的序列化场景,例如处理继承关系、接口、匿名类型等,此时需要更深入地理解和应用这些知识。

    JAVA对象的序列化与反序列化详细PPT课件.pptx

    另外,还有`java.io.Externalizable`接口,它继承自`Serializable`,但提供了更细粒度的控制权,允许类自定义序列化和反序列化的行为。如果一个类实现了`Externalizable`,则需要手动实现`writeExternal...

    delphi 序列化

    序列化 (serialization):将对象的状态信息转换为可以存储或传输的形式的过程...在Delphi中 只要从 TPersistent继承后就会有序列化的功能。 在TPersistent中的定义 procedure DefineProperties(Filer: TFiler); virtual;

    J2SE中的序列化之继承

    总结来说,Java序列化机制为类提供了一种透明的方式来保存和恢复对象状态,继承系统中的序列化行为是自动的。当父类未实现`Serializable`时,子类仍可以通过承担序列化父类字段的责任来实现序列化,但这通常需要更多...

    c#对象序列化和反序列化,压缩流

    在C#编程中,对象序列化和反序列化是至关重要的技术,它们允许我们将对象的状态转化为可存储或可传输的数据格式,例如XML、JSON或二进制,以便于保存、恢复或者在网络间传递。而“压缩流”则涉及到数据的压缩和解...

    Json序列化和反序列化

    如果需要自定义JSON序列化和反序列化的逻辑,可以创建继承自`JsonConverter`的类。然后,你可以在数据合同类上使用`[JsonConverter]`特性来指定该转换器。 5. 动态对象 Json.NET也支持直接将JSON字符串反序列化为...

    Gson 枚举类型的统一序列化/反序列化处理

    要实现自定义的枚举序列化和反序列化,我们需要创建一个继承自`Gson.TypeAdapter`的类。这个类需要重写`read()`和`write()`方法。`read()`方法负责将JSON解析为枚举值,而`write()`方法则将枚举值转化为JSON。下面是...

    java序列化全解

    1. **继承性**:如果一个类是可序列化的,那么它的所有子类也将自动成为可序列化的。然而,如果父类没有实现`Serializable`接口,那么只有子类中定义的字段会被序列化,而父类的字段不会。 2. **静态和transient...

    序列化、反序列化源码

    在编程领域,序列化和反序列化是两个重要的概念,特别是在数据存储、网络通信和对象持久化等场景中。本文将深入探讨这两个概念,并结合基于VS2005的C++实现来阐述其核心思想。 **序列化**是指将一个对象的状态转换...

    C#自定义序列化ISerializable的实现方法

    在C#编程中,序列化是一个重要的概念,它允许对象的状态被转换为可存储或传输的数据格式。ISerializable接口是.NET Framework提供的一种自定义序列化的方式,允许开发者精确控制对象的序列化和反序列化过程。下面...

    Java_序列化的高级认识

    在Java中,子类继承自父类时,如果父类可序列化,那么子类默认也是可序列化的。然而,这可能会引发一些意料之外的问题,尤其是当父类中有敏感信息或者不希望被序列化的字段时。此时,`transient`关键字的作用就显得...

    MFC序列化应用示例

    MFC序列化是通过继承自CObject类的对象实现的,使得这些对象能够将自己转换为字节流,然后可以被存储到文件或数据库中,也可以从这些存储源中恢复。这个过程对于数据的保存和加载非常有用,特别是在需要长期保存应用...

    关于 Java 对象序列化您不知道的 5 件事

    Java对象序列化是Java平台的一项重要特性,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在本文中,我们将深入探讨关于Java对象...通过以上这些知识点,你应该能更好地应对日常开发中与序列化相关的问题。

Global site tag (gtag.js) - Google Analytics