Java中带有继承的对象序列化
先决条件:序列化、继承
序列化是一种将对象的状态转换为字节流的机制。字节数组可以是对象的类、版本和内部状态。
反序列化是使用字节流在内存中重新创建实际Java对象的逆过程。该机制用于持久化对象。
有一些关于继承的序列化案例:
情况1:如果超类是可序列化的,那么子类是自动可序列化的
如果超类是可序列化的,那么默认情况下,每个子类都是可序列化的。因此,即使子类没有实现 Serializable 接口(如果它的超类实现了 Serializable),我们也可以序列化子类对象。
Java
// Java program to demonstrate
// that if superclass is
// serializable then subclass
// is automatically serializable
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// superclass A
// implementing Serializable interface
class A implements Serializable
{
int i;
// parameterized constructor
public A(int i)
{
this.i = i;
}
}
// subclass B
// B class doesn't implement Serializable
// interface.
class B extends A
{
int j;
// parameterized constructor
public B(int i, int j)
{
super(i);
this.j = j;
}
}
// Driver class
public class Test
{
public static void main(String[] args)
throws Exception
{
B b1 = new B(10,20);
System.out.println("i = " + b1.i);
System.out.println("j = " + b1.j);
/* Serializing B's(subclass) object */
//Saving of object in a file
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// Method for serialization of B's class object
oos.writeObject(b1);
// closing streams
oos.close();
fos.close();
System.out.println("Object has been serialized");
/* De-Serializing B's(subclass) object */
// Reading the object from a file
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for de-serialization of B's class object
B b2 = (B)ois.readObject();
// closing streams
ois.close();
fis.close();
System.out.println("Object has been deserialized");
System.out.println("i = " + b2.i);
System.out.println("j = " + b2.j);
}
}
Java
// Java program to demonstrate
// the case if superclass need
// not to be serializable
// while serializing subclass
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// superclass A
// A class doesn't implement Serializable
// interface.
class A {
int i;
// parameterized constructor
public A(int i){
this.i = i;
}
// default constructor
// this constructor must be present
// otherwise we will get runtime exception
public A()
{
i = 50;
System.out.println("A's class constructor called");
}
}
// subclass B
// implementing Serializable interface
class B extends A implements Serializable {
int j;
// parameterized constructor
public B(int i, int j)
{
super(i);
this.j = j;
}
}
// Driver class
public class Test {
public static void main(String[] args) throws Exception
{
B b1 = new B(10, 20);
System.out.println("i = " + b1.i);
System.out.println("j = " + b1.j);
// Serializing B's(subclass) object
// Saving of object in a file
FileOutputStream fos
= new FileOutputStream("abc.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
// Method for serialization of B's class object
oos.writeObject(b1);
// closing streams
oos.close();
fos.close();
System.out.println("Object has been serialized");
// De-Serializing B's(subclass) object
// Reading the object from a file
FileInputStream fis
= new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for de-serialization of B's class object
B b2 = (B)ois.readObject();
// closing streams
ois.close();
fis.close();
System.out.println("Object has been deserialized");
System.out.println("i = " + b2.i);
System.out.println("j = " + b2.j);
}
}
Java
// Java program to demonstrate
// how to prevent
// subclass from serialization
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// superclass A
// implementing Serializable interface
class A implements Serializable
{
int i;
// parameterized constructor
public A(int i)
{
this.i = i;
}
}
// subclass B
// B class doesn't implement Serializable
// interface.
class B extends A
{
int j;
// parameterized constructor
public B(int i,int j)
{
super(i);
this.j = j;
}
// By implementing writeObject method,
// we can prevent
// subclass from serialization
private void writeObject(ObjectOutputStream out) throws IOException
{
throw new NotSerializableException();
}
// By implementing readObject method,
// we can prevent
// subclass from de-serialization
private void readObject(ObjectInputStream in) throws IOException
{
throw new NotSerializableException();
}
}
// Driver class
public class Test
{
public static void main(String[] args)
throws Exception
{
B b1 = new B(10, 20);
System.out.println("i = " + b1.i);
System.out.println("j = " + b1.j);
// Serializing B's(subclass) object
//Saving of object in a file
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// Method for serialization of B's class object
oos.writeObject(b1);
// closing streams
oos.close();
fos.close();
System.out.println("Object has been serialized");
// De-Serializing B's(subclass) object
// Reading the object from a file
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for de-serialization of B's class object
B b2 = (B)ois.readObject();
// closing streams
ois.close();
fis.close();
System.out.println("Object has been deserialized");
System.out.println("i = " + b2.i);
System.out.println("j = " + b2.j);
}
}
输出:
i = 10
j = 20
Object has been serialized
Object has been deserialized
i = 10
j = 20
情况2:如果超类不可序列化,那么子类仍然可以序列化
即使超类没有实现 Serializable 接口,如果子类本身实现了 Serializable 接口,我们也可以序列化子类对象。所以我们可以说要序列化子类对象,超类不需要是可序列化的。但是在这种情况下,在序列化过程中超类的实例会发生什么。以下过程对此进行了说明。
案例 2(a):当一个类是可序列化的,但它的超类不是时会发生什么?
序列化:在序列化时,如果任何实例变量继承自不可序列化的超类,那么 JVM 会忽略该实例变量的原始值并将默认值保存到文件中。
反序列化:在反序列化的时候,如果存在任何不可序列化的超类,那么JVM会在超类中执行实例控制流。要在类中执行实例控制流,JVM 将始终调用该类的默认(无参数)构造函数。因此,每个不可序列化的超类都必须包含一个默认构造函数。否则,我们将得到一个运行时异常。
Java
// Java program to demonstrate
// the case if superclass need
// not to be serializable
// while serializing subclass
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// superclass A
// A class doesn't implement Serializable
// interface.
class A {
int i;
// parameterized constructor
public A(int i){
this.i = i;
}
// default constructor
// this constructor must be present
// otherwise we will get runtime exception
public A()
{
i = 50;
System.out.println("A's class constructor called");
}
}
// subclass B
// implementing Serializable interface
class B extends A implements Serializable {
int j;
// parameterized constructor
public B(int i, int j)
{
super(i);
this.j = j;
}
}
// Driver class
public class Test {
public static void main(String[] args) throws Exception
{
B b1 = new B(10, 20);
System.out.println("i = " + b1.i);
System.out.println("j = " + b1.j);
// Serializing B's(subclass) object
// Saving of object in a file
FileOutputStream fos
= new FileOutputStream("abc.ser");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
// Method for serialization of B's class object
oos.writeObject(b1);
// closing streams
oos.close();
fos.close();
System.out.println("Object has been serialized");
// De-Serializing B's(subclass) object
// Reading the object from a file
FileInputStream fis
= new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for de-serialization of B's class object
B b2 = (B)ois.readObject();
// closing streams
ois.close();
fis.close();
System.out.println("Object has been deserialized");
System.out.println("i = " + b2.i);
System.out.println("j = " + b2.j);
}
}
输出:
i = 10
j = 20
Object has been serialized
A's class constructor called
Object has been deserialized
i = 50
j = 20
案例3:如果超类是可序列化的,但我们不希望子类被序列化
没有直接的方法可以防止子类在Java中序列化。程序员实现此目的的一种可能方法是在子类中实现writeObject()和readObject()方法,并且需要从这些方法中抛出NotSerializableException 。这些方法分别在序列化和反序列化期间执行。通过覆盖这些方法,我们只是在实现我们的自定义序列化。
Java
// Java program to demonstrate
// how to prevent
// subclass from serialization
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// superclass A
// implementing Serializable interface
class A implements Serializable
{
int i;
// parameterized constructor
public A(int i)
{
this.i = i;
}
}
// subclass B
// B class doesn't implement Serializable
// interface.
class B extends A
{
int j;
// parameterized constructor
public B(int i,int j)
{
super(i);
this.j = j;
}
// By implementing writeObject method,
// we can prevent
// subclass from serialization
private void writeObject(ObjectOutputStream out) throws IOException
{
throw new NotSerializableException();
}
// By implementing readObject method,
// we can prevent
// subclass from de-serialization
private void readObject(ObjectInputStream in) throws IOException
{
throw new NotSerializableException();
}
}
// Driver class
public class Test
{
public static void main(String[] args)
throws Exception
{
B b1 = new B(10, 20);
System.out.println("i = " + b1.i);
System.out.println("j = " + b1.j);
// Serializing B's(subclass) object
//Saving of object in a file
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// Method for serialization of B's class object
oos.writeObject(b1);
// closing streams
oos.close();
fos.close();
System.out.println("Object has been serialized");
// De-Serializing B's(subclass) object
// Reading the object from a file
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
// Method for de-serialization of B's class object
B b2 = (B)ois.readObject();
// closing streams
ois.close();
fis.close();
System.out.println("Object has been deserialized");
System.out.println("i = " + b2.i);
System.out.println("j = " + b2.j);
}
}
输出:
i = 10
j = 20
Exception in thread "main" java.io.NotSerializableException
at B.writeObject(Test.java:44)