Java基础是指序列化(シリアライズ)是什么?
上一次,我编写了生成文件对象并进行写入和读取字符的操作。
这一次,我想写关于如何使用程序员创建的类来生成对象并进行输入输出的方法。
序列化
这是将生成的实例转换为字节序列(序列化)并将该字节序列还原为实例(反序列化)的机制。
通过这个机制,可以使用输入输出流将其保存到文件中或通过网络传输。
序列化也称为串行化。
使对象可以序列化
为了使普通类能够被序列化,必需实现java.io.Serializable接口。该接口是一个标记接口,没有需要重写的方法。
以下的程序中,Person类实现了Serializable接口,使其成为可序列化的对象。
import java.io.*;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name = "";
private int age = 0;
private transient String language = "Japanese";
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getInfo() {
return name + ":" + age;
}
public String getLang() {
return language;
}
}
为了输入和输出数据,创建流。
可序列化对象的输入和输出可以使用ObjectOutputStream类和ObjectOutputStream类。通过使用这些流,可以将实例保存到外部或从外部恢复。
以下的程序将通过流的方式将在前面的Person类中创建的实例保存到文件中,并从文件中恢复。
public class Main {
public static void main(String[] args) {
try (ObjectOutputStream outObject = new ObjectOutputStream(new FileOutputStream("object.txt"));
ObjectInputStream inObject = new ObjectInputStream(new FileInputStream("object.txt"));) {
outObject.writeObject(new Person("Taro",22));
Person exP = (Person)inObject.readObject();
System.out.println(exP.getInfo());
System.out.println(exP.getLang());
} catch (IOException | ClassNotFoundException e) {
}
}
}
生成具有名为「object.txt」的路径的FileOutputStream和FileInputStream对象,并使用它们生成ObjectOutputStream和ObjectInputStream对象。
然后,通过writeObject()方法指定的对象(直接生成名为”太郎,22岁”的Person对象),经过ObjectOutputStream,写入到”object.txt”文件中。
此外,使用readObject()方法将保存在”object.txt”中的实例恢复并存储在Person类的变量中。由于readObject()方法的返回值是Object类型,因此在将其赋值给exP之前,必须将其强制转换为Person类类型。
由于readObject()方法有可能抛出ClassNotFindException,因此需要编写相应的异常处理代码。
顺便说一下,如果执行上述程序,会得到以下结果的输出。
Taro:22
null
请参考下面关于“transient”关键字的说明,这就是为什么第二行出现了null的原因。
不需要序列化的变量。
即使实现了Serializable接口的类,以下的变量也无法进行序列化:
– 被标记为transient的变量
– 静态变量
– 类型为未实现Serializable接口的类的变量
transient 在反序列化时会以null的状态恢复。刚才的程序中,返回null也是由于这个原因。另外,静态变量由于在静态区域保存了值,在恢复时会使用那里的值。
序列化继承
可以自动进行序列化,而不需要在可序列化的类的子类中显式写出”implements Serializable”。
此外,如果超类未实现Serializable接口,而子类实现了Serializable接口,在反序列化过程中,超类的构造函数将被调用以实例化对象。
序列号
在Person类的字段中声明了一个名为”serialVersionUID”的常量。
这个常量是用来识别在恢复之前和之后是否对类进行了更改的序列化版本ID。(在eclipse中,如果不写这个常量会收到警告。)
在修改类时修改序列版本ID,当您尝试使用修改后的类来恢复之前保存的实例时,会发生异常(InvalidClassException)。通过这种方式,可以通知在恢复时发生了不一致的情况。
<参考来源>
书籍:
– 《轻松学习Java入门 实践篇 第2版》
– 《Oracle认证教材 Java程序员 Gold SE 8》
网页:
– 《真人快打的玩家技术备忘录》
http://piyopiyocs.blog115.fc2.com/blog-entry-205.html