文章目录
一、序列化和反序列化的理解
什么是序列化?
序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据
二、通过对象专属流实现序列化
一个对象序列化的接口,一个类只有实现了Serializable
接口,它的对象才能被序列化。
参与序列化和反序列化的对象,必须实现Serializable
接口
注意:
通过源码发现,Serializeable
接口只是一个标志接口:
public interface Serializable{
}
这个接口什么代码都没有,那么他有什么作用呢?
起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,会对这个类进行特殊待遇,JVM看到Serializeable
接口后,会为该类自动生成一个序列化版本号。
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ObjectOutputStreamTest {
public static void main(String[] args) throws Exception {
//创建对象
Student s = new Student(1111,"zhangsan");
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
//序列化对象
oos.writeObject(s);
oos.flush();
oos.close();
}
}
三、序列化版本号
Java虚拟机会默认提供序列版本号。如果类的源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
建议将序列版本号手动写出来,不建议自动生成。
class Student implements Serializable {
private static final long serialVersionUID = 1L;//手动写出序列号
private int no;
private String name;
java语言是采用什么样的机制来区分分类的?
- 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类
- 第二:如果类名一样,靠序列化版本号进行区分。
小鹏编写了一个类: com . bjipowernode . java. bean. Student implements Serial izable
胡浪编写了一个类: com . bjpowernode. java. bean. Student implements Serial izable扫描二维码关注公众号,回复: 13138011 查看本文章![]()
不同的人编写了同一个类,但“这两个类确实不是同一个类”。这个时候序列化版本就起上作用了。
对于java虚拟机来说, java虚拟机是可以区分开这两个类的,因为这两个类都实现了Serializable
接口,都有默认的序列化版本号,他们的序列化版本号不一样。所以区分开了。( 这是自动生成序列化版本号的好处)
这种自动生成序列化版本号有什么缺陷?
这种自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。( 这样就不好了! )
结论:
凡是一个类实现了Serializable
接口,建议给该类提供一个固定不变的序列化版本号。
这样,即使以后这个类代码修改了,但是版本号不变,java虚拟机会认为是同一个类
IDEA生成序列化版本号
File -> Settings -> Editor -> Inspections -> 搜索serializable -> 选中Serializable classes Without a serialVersionUID -> Apply
然后再类名上:Alt+回车
四、通过对象专属流实现反序列化
import java.io.Serializable;
class Student implements Serializable {
private int no;
private String name;
public Student(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ObjectInputStreamTest {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
//开始反序列化
Object obj = ois.readObject();
//反序列化回来是一个学生对象,所以会调用学生对象的toString方法
System.out.println(obj);
ois.close();
}
}
五、序列化多个对象
把对象放入集合中去,序列化集合。
class User implements Serializable {
private int no;
private String name;
public User() {
}
public User(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ObjectOutputStreamTest2 {
public static void main(String[] args) throws IOException {
List<User> userList = new ArrayList<>();
userList.add(new User(1,"zhangsan"));
userList.add(new User(2,"lisi"));
userList.add(new User(3,"wangwu"));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));
//序列化一个集合,这个集合对象中放了很多其他的对象
oos.writeObject(userList);
oos.flush();
oos.close();
}
}
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;
public class ObjectInputStreamTest2 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("users"));
List<User> userList = (List<User>)ois.readObject();
for(User users: userList){
System.out.println(users);
}
ois.close();
}
}
运行结果:
六、transient关键字
transient
关键字表示游离的,不参与序列化
User类加入transient
关键字修改:
private transient String name;
再次运行结果: