小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
java 对象经常需要在网络中以 socket 传输或者需要保存到文件中。这时不管 java 对象是文件、数据、图像还是其他格式,都可以转换为一个 byte[] 数组保存到文件或者通过网络传输。这种转换方式就叫做序列化。将文件或者网络传输中得到的 byte[] 数组转换为 java 对象就叫做反序列化。
怎么使用
如果一个 Java 对象要能被序列化,必须实现一个特殊的 java.io.Serializable 接口
public interface Serializable { }
复制代码
Serializable 接口没有定义任何的方法,是一个空接口。为什么要有一个这样的接口?主要是因为安全。如果没有这个接口就代表着所有 java 对象都可以被序列化到磁盘上,然后通过反序列化看到所有属性的数据。有了这个 Serializable 就可以让开发人员选择 java 对象可以被序列化和反序列化,就增加了安全性。
序列化
下面例子是将一个 java 对象序列化后保存到文件。
public class Person implements Serializable {
private String name;
private int age;
private String hobby;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
复制代码
把一个 Java 对象变为 byte[] 数组,需要使用 ObjectOutputStream。它负责把一个Java 对象写入一个字节流:
public class Test {
public static void main(String[] args) throws Exception {
Person person1 = new Person();
person1.setAge(18);
person1.setName("小马");
person1.setHobby("画画");
Person person2 = new Person();
person2.setAge(50);
person2.setName("小军");
person2.setHobby("钓鱼");
List<Person> list = new ArrayList<>();
list.add(person1);
list.add(person2);
FileOutputStream fos = new FileOutputStream("D:\\person.txt");
try ( ObjectOutputStream os = new ObjectOutputStream(fos)){
os.writeObject(list);
}
System.out.println("序列化成功");
}
}
复制代码
这个时候就将两个 Person 对象序列化到了 D:\person.txt 中。打开文件,里面应该都是乱码,如下图:
反序列化
序列化文件在本地打开都是乱码的,这应该用反序列化将文件解析成对象。
public static void main(String[] args) throws Exception{
List<Person> list = new ArrayList<>();
FileInputStream fis = new FileInputStream("D:\\person.txt");
try (ObjectInputStream is = new ObjectInputStream(fis)) {
list = (List<Person>)is.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
for (Person person : list){
System.out.println(person.toString());
}
}
复制代码
输出结果:
Person{name='小马', age=18, hobby='画画'}
Person{name='小军', age=50, hobby='钓鱼'}
复制代码
注意点
- 静态变量和 transient 关键字修饰的变量不能被序列化
- 反序列化的时候,字节流中的 serialVersionUID 和实体类中的 serialVersionUID 的不一致会抛出异常。serialVersionUID 没有写的话,会被默认一个。
- 序列化实现了深克隆,对象引用的每一个对象数据也会被序列化。
总结
- 序列化必须实现 Serializable。
- serialVersionUID 不是必须的。
近期评论