import java.io.Serializable;
/**
* 编写一个Student类
*/
public class Student implements Serializable {
//IDEA工具可以自动生成序列化版本号
// Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。
// 这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
// 建议将序列化版本号手动的写出来。不建议自动生成
//如果没有将序列化版本号写出来
// 过了很久,Student这个类源代码改动了。
// 源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。
// 并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
//运行反序列化代码时会出现以下错误:
/**java.io.InvalidClassException: Student;
* local class incompatible: stream classdesc serialVersionUID = 1313054788157907747,
* * local class serialVersionUID = -5157370501780678174*/
//运行前后Student类序列化版本号不同
//手动写出序列化版本号,以后修改Student类反序列化不会报错
private static final long serialVersionUID=1L;
private int no;
private int age;
private String email;
private String address;
public Student() {
}
public Student(int no, String email) {
this.no = no;
this.email = email;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
",age="+age+
",email="+email+
",address="+address+"}";
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* 序列化Student类对象
* 1、java.io.NotSerializableException:
* 不支持序列化!!!!
*
* 2、参与序列化和反序列化的对象,必须在参与序列化的对象所在类实现Serializable接口。
*
* 3、注意:通过源代码发现,Serializable接口只是一个标志接口:
* public interface Serializable {
* }
* 这个接口当中什么代码都没有。
* 那么它起到一个什么作用呢?
* 起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。
* Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成
* 一个序列化版本号。
*
*
* java语言中是采用什么机制来区分类的?
* 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
* 第二:如果类名一样,再怎么进行类的区别?靠序列化版本号进行区分。
*
* 小鹏编写了一个类:com.bjpowernode.java.bean.Student implements Serializable
* 胡浪编写了一个类:com.bjpowernode.java.bean.Student implements Serializable
* 不同的人编写了同一个类,但“这两个类确实不是同一个类”。这个时候序列化版本就起上作用了。
* 对于java虚拟机来说,java虚拟机是可以区分开这两个类的,因为这两个类都实现了Serializable接口,
* 都有默认的序列化版本号,他们的序列化版本号不一样。所以区分开了。(这是自动生成序列化版本号的好处)
*
* 请思考?
* 这种自动生成序列化版本号有什么缺陷?
* 这种自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续的修改,
* 因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java
* 虚拟机会认为这是一个全新的类。(这样就不好了!)
*
* 最终结论:
* 凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。
* 这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类。
*
* */
public class ObjectOutputStreamTest01 {
public static void main(String[] args) {
//创建Student对象
Student s=new Student(1111,"zhangsan");
ObjectOutputStream oos=null;
try {
//序列化:Serialize java对象存储到文件中,将java对象的状态保存下来的过程
oos=new ObjectOutputStream(new FileOutputStream("students"));
//序列化对象
oos.writeObject(s);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
*反序列化:DeSerialize 将硬盘上的数据重新恢复到内存当中,恢复成java对象
*/
public class ObjectInputStreamTest01 {
public static void main(String[] args) {
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(new FileInputStream("students"));
// 开始反序列化,读
Object obj=ois.readObject();
// 反序列化回来是一个学生对象,所以会调用学生对象的toString方法。
System.out.println(obj);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
if(ois!=null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
序列化结果:

反序列化结果如下:

本文深入探讨了Java对象的序列化与反序列化,包括序列化的作用、序列化版本号的重要性以及如何手动指定序列化版本号以避免类修改后的不兼容问题。示例代码展示了如何实现序列化和反序列化操作,强调了序列化版本号在类更新后保持不变以确保反序列化成功的必要性。

675

被折叠的 条评论
为什么被折叠?



