Java序列化简介
最后修改:2019年5月21日
1.介绍
序列化是将对象的状态转换为字节流;反序列化则相反。换一种说法,序列化是将Java对象转换为静态字节流(序列),然后可以将其保存到数据库中或通过网络传输。
2.序列化和反序列化
序列化过程是独立于实例的,也就是说,对象可以在一个平台上序列化,在另一个平台上反序列化。符合序列化条件的类需要实现一个特殊的标记接口可序列化的。
这两个ObjectInputStream和ObjectOutputStream高级类是扩展的吗java.io.InputStream和java.io.OutputStream分别。ObjectOutputStream可以将对象的基本类型和图写入OutputStream作为字节流。这些流随后可以使用ObjectInputStream。
最重要的方法ObjectOutputStream是:
public final void writeObject(Object o) throws IOException;
它接受一个可序列化对象并将其转换为一个字节序列(流)。同样,最重要的方法ObjectInputStream是:
public final Object readObject() throws IOException, ClassNotFoundException;
它可以读取字节流并将其转换回Java对象。然后可以将其转换回原始对象。
让我们用人类。请注意,静态字段属于类(相对于对象),并且没有序列化。另外,请注意,我们可以使用关键字瞬态在序列化过程中忽略类字段:
public class Person implements Serializable {private static final long serialVersionUID = 1L;static String country = "意大利";私人int年龄;私人字符串名称;瞬态int高度;//获取和设置
下面的测试显示了一个保存类型对象的示例人到一个本地文件,然后读回这个值:
@Test public void whenSerializingAndDeserializing_ThenObjectIsTheSame()()抛出IOException, ClassNotFoundException {Person Person = new Person();person.setAge (20);person.setName(“乔”);FileOutputStream = new FileOutputStream("yourfile.txt");ObjectOutputStream ObjectOutputStream = new ObjectOutputStream(fileOutputStream);objectOutputStream.writeObject(人);objectOutputStream.flush ();objectOutputStream.close ();FileInputStream = new FileInputStream("yourfile.txt");ObjectInputStream ObjectInputStream = new ObjectInputStream(fileInputStream); Person p2 = (Person) objectInputStream.readObject(); objectInputStream.close(); assertTrue(p2.getAge() == p.getAge()); assertTrue(p2.getName().equals(p.getName())); }
我们使用ObjectOutputStream用于将此对象的状态保存到文件中FileOutputStream。该文件“yourfile.txt”在项目目录中创建。然后使用FileInputStream。ObjectInputStream拾取此流并将其转换为名为p2。
最后,我们测试加载对象的状态,它与原始对象的状态匹配。
注意,加载的对象必须显式转换为人类型。
3.Java序列化的警告
关于Java中的序列化,有一些需要注意的事项。
3.1。继承和组合
类实现java.io.Serializable接口,它的所有子类也是可序列化的。相反,当一个对象有对另一个对象的引用时,这些对象必须实现可序列化的接口,否则NotSerializableException将被扔:
public class Person implements Serializable {private int age;私人字符串名称;私有地址;//也必须是可序列化的}
如果可序列化对象中的一个字段由一个对象数组组成,那么所有这些对象也必须是可序列化的,否则NotSerializableException将抛出。
3.2。串行版本UID
JVM关联一个版本(长)编号,每个序列化类。它用于验证保存的和加载的对象具有相同的属性,因此在序列化时是兼容的。
这个数字可以由大多数ide自动生成,它基于类名、类的属性和相关的访问修饰符。任何更改都会导致不同的数字,并可能导致InvalidClassException。
如果可序列化类没有声明serialVersionUID, JVM将在运行时自动生成一个。但是,强烈建议每个类声明它serialVersionUID因为生成的是依赖于编译器的,因此可能会导致意外的结果InvalidClassExceptions。
3.3。Java中的自定义序列化
Java指定了对象序列化的默认方式。Java类可以覆盖这个默认行为。当试图序列化具有一些不可序列化属性的对象时,自定义序列化可能特别有用。这可以通过在想要序列化的类内部提供两个方法来实现:
私有void writeObject(ObjectOutputStream out) throws IOException;
和
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
通过这些方法,我们可以将这些非序列化的属性序列化为其他可以序列化的形式:
public class Employee implements Serializable {private static final long serialVersionUID = 1L;私有暂态地址地址;个人人;//私有void writeObject(ObjectOutputStream oos) throws IOException {oos. defaultwriteobject ();oos.writeObject (address.getHouseNumber ());} private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {ois. defaultreadobject ();Integer houseNumber = (Integer) ois.readObject();地址a = new Address();a.setHouseNumber (houseNumber);this.setAddress(一个); } }
public class Address {private int houseNumber;//设置变量
以下单元测试测试此自定义序列化:
@Test public void whenCustomSerializingAndDeserializing_ThenObjectIsTheSame() throws IOException, ClassNotFoundException {Person p = new Person();p.setAge (20);p.setName(“乔”);地址a = new Address();a.setHouseNumber (1);雇员e =新雇员();e.setPerson (p);e.setAddress(一个);FileOutputStream = new FileOutputStream("yourfile2.txt");ObjectOutputStream ObjectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(e); objectOutputStream.flush(); objectOutputStream.close(); FileInputStream fileInputStream = new FileInputStream("yourfile2.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Employee e2 = (Employee) objectInputStream.readObject(); objectInputStream.close(); assertTrue( e2.getPerson().getAge() == e.getPerson().getAge()); assertTrue( e2.getAddress().getHouseNumber() == e.getAddress().getHouseNumber()); }
在这段代码中,我们看到了如何通过序列化保存一些不可序列化的属性地址自定义序列化。注意,我们必须将不可序列化的属性标记为瞬态为了避免NotSerializableException。
4.结论
在本快速教程中,我们回顾了Java序列化,讨论了需要记住的重要事项,并展示了如何进行自定义序列化。
和往常一样,本教程中使用的源代码是可用的在GitHub。