📅  最后修改于: 2023-12-03 15:31:49.437000             🧑  作者: Mango
在Java中,对象序列化是将对象转换成字节流的过程。这个过程可以用来在不同的应用程序之间传递对象或者将对象存储到文件或数据库等持久化存储中。
当使用Java中带有继承的类进行对象序列化时,需要注意一些细节。
考虑下面这个带有继承的类:
class Person implements Serializable {
private String name;
private int age;
// constructors, getters, and setters
}
class Student extends Person implements Serializable {
private String major;
// constructors, getters, and setters
}
在这个例子中,Person
是一个基类,Student
是一个子类。
如果想要序列化一个Student
对象,只需要将Student
类声明为Serializable
,Java序列化机制会自动序列化Person
类中的字段。
Student student = new Student("Alice", 20, "Computer Science");
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.ser"))) {
oos.writeObject(student);
} catch (IOException e) {
e.printStackTrace();
}
在上面的示例中,Student
对象被写入到student.ser
文件中。
如果要反序列化该对象,只需要使用ObjectInputStream
读取文件并调用readObject()
方法即可。
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.ser"))) {
Student student = (Student) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
如果想要序列化一个基类对象,那么该基类也必须要实现Serializable
接口。否则,在序列化子类时会抛出NotSerializableException
异常。
class Person {
...
}
class Student extends Person implements Serializable {
...
}
在这个例子中,Person
没有实现Serializable
接口,因此尝试序列化Student
时,会抛出NotSerializableException
异常。
Student student = new Student("Alice", 20, "Computer Science");
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.ser"))) {
oos.writeObject(student);
} catch (IOException e) {
e.printStackTrace();
}
会得到如下异常:
java.io.NotSerializableException: Person
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
...
为了解决这个问题,可以让Person
也实现Serializable
接口。
class Person implements Serializable {
...
}
class Student extends Person implements Serializable {
...
}
这样,就可以正常地序列化Student
对象。
如果有多层继承关系,那么在序列化子类时,Java序列化机制会自动序列化父类。
class Person implements Serializable {
...
}
class Student extends Person implements Serializable {
...
}
class GraduateStudent extends Student implements Serializable {
...
}
在这个例子中,GraduateStudent
是Student
的子类,Student
是Person
的子类。在序列化GraduateStudent
对象时,Student
和Person
的数据都会被序列化。因此,Person
和Student
也必须实现Serializable
接口。
GraduateStudent graduateStudent = new GraduateStudent("Bob", 25, "Computer Science", "Machine Learning");
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("graduateStudent.ser"))) {
oos.writeObject(graduateStudent);
} catch (IOException e) {
e.printStackTrace();
}
如果不想序列化某个父类字段,可以使用transient
关键字。
class Person implements Serializable {
private String name;
private transient int age;
...
}
class Student extends Person implements Serializable {
private String major;
...
}
在这个例子中,Person
类中的age
字段被声明为transient
,即不会被序列化。在序列化Student
对象时,Person
类中的name
字段会被序列化,但age
字段不会被序列化。
如果需要对序列化和反序列化过程进行更精细的控制,可以实现Serializable
接口中的writeObject()
和readObject()
方法。
class Student extends Person implements Serializable {
private String major;
...
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
...
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
...
}
}
在这个例子中,writeObject()
方法会在序列化Student
对象时被调用,readObject()
方法会在反序列化Student
对象时被调用。在这些方法中,可以自己编写序列化和反序列化的实现。
在Java中,使用带有继承的类进行对象序列化时,需要将所有类声明为Serializable
。在序列化多层继承关系时,所有父类都会被序列化。如果需要对序列化和反序列化过程进行更精细的控制,可以实现writeObject()
和readObject()
方法。