序列化:将java对象转换为字节序列
反序列化:把字节序列恢复成原本的java对象
序列化的作用:在传递和保存对象时,保证对象的完整性和可传递性。对象转换为有序字节流,也方便在网络上传输或者保存到本地文件
反序列化的作用:根据字节流中保存的对象状态集描述信息,通过反序列化重建对象
Student类定义
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student implements Serializable {
private String name;
private Integer age;
private Integer score;
}
序列化
public class DemoSerializable {
public static void main(String[] args) throws IOException {
Student student = new Student();
student.setName("CodeSheep");
student.setAge(18);
student.setScore(1000);
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream("student.txt"));
objectOutputStream.writeObject(student);
objectOutputStream.close();
System.out.println("序列化成功!已经生成student.txt文件");
System.out.println("==============================================");
}
}
反序列化
public class DemoDeserialize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream =
new ObjectInputStream( new FileInputStream("student.txt") );
Student student = (Student) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化结果为:");
System.out.println( student );
}
}
这里我们可以点进去Serializable
接口,查看源码,发现这是一个空接口
这里我们试想一下,加入Student类不实现Serializable接口,会发送什么情况呢?
此时的程序运行会报错,并抛出NotSerializableException
异常:
我们按照错误提示,由源码一直跟到ObjectOutputStream
的writeObject0()
方法底层看一看:
查看源码可知:如果一个对象既不是字符串、数组、枚举,而且也没有实现Serializable
接口的话,在序列化时就会抛出NotSerializableException
异常!Serializable
接口也仅仅只是做一个标记用,它告诉代码只要是实现了Serializable
接口的类都是可以被序列化的!然而真正的序列化动作不需要靠它完成
我们有时候可以在一些类中看到如下的代码,那他到底有什么作用呢?
private static final long serialVersionUID = -4392658638228508589L;
下面我们来做一个小实验,先让Student类实现Serializable接口,然后执行序列化的方法
public class DemoSerializable {
public static void main(String[] args) throws IOException {
Student student = new Student();
student.setName("CodeSheep");
student.setAge(18);
student.setScore(1000);
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream("student.txt"));
objectOutputStream.writeObject(student);
objectOutputStream.close();
System.out.println("序列化成功!已经生成student.txt文件");
System.out.println("==============================================");
}
}
然后在student类添加一个字段
这时候,我们拿刚才已经序列化到本地的student.txt
文件,还用如下代码进行反序列化,试图还原出刚才那个Student
对象:
public class DemoDeserialize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream =
new ObjectInputStream( new FileInputStream("student.txt") );
Student student = (Student) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化结果为:");
System.out.println( student );
}
}
这地方提示的信息非常明确了:序列化前后的serialVersionUID
号码不兼容!
结论:
serialVersionUID
,那编译器会为它自动声明一个serialVersionUID
序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程
如果在定义一个可序列化的类时,没有人为显式地给它定义一个serialVersionUID
的话,则Java运行时环境会根据该类的各方面信息自动地为它生成一个默认的serialVersionUID
,一旦像上面一样更改了类的结构或者信息,则类的serialVersionUID
也会跟着变化!
所以,为了serialVersionUID
的确定性,写代码时还是建议,凡是implements Serializable
的类,都最好人为显式地为它声明一个serialVersionUID
明确值
static
修饰的字段是不会被序列化的transient
修饰符修饰的字段也是不会被序列化的对于第一点,因为序列化保存的是对象的状态而非类的状态,所以会忽略static
静态域也是理所应当的
对于第二点,就需要了解一下transient
修饰符的作用了
如果在序列化某个类的对象时,就是不希望某个字段被序列化(比如这个字段存放的是隐私值,如:密码
等),那这时就可以用transient
修饰符来修饰该字段
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_43296313/article/details/123401000
内容来源于网络,如有侵权,请联系作者删除!