JAVA序列化

转载自:https://mp.weixin.qq.com/s?__biz=MzU4ODI1MjA3NQ==&mid=2247486849&idx=1&sn=c0a2555ba22921187a28547b66877af8&chksm=fddedb45caa95253141832de26e0622ed555474082f0831b35e4277e086c01990116a60d16a2&mpshare=1&scene=1&srcid=05315R3aUi5pcI6rPN8kkynZ&sharer_sharetime=1590912444906&sharer_shareid=13cf2778adeca2417cfaf1c438b3ccca&key=88af3932a9de156efea0c6d68ac339b2ac105c6e72603ebc0c7c5232e9703b584615890c60eb1d97f12ab421cc1bab6404d094d743398ab60fd6acc603d79f8a57dfde5e079e1434e6f6a4afb014d75e&ascene=1&uin=MjczMDAzNTQwMw%3D%3D&devicetype=Windows+10+x64&version=6209007b&lang=zh_CN&exportkey=AfwsIWNHKtRntszCVzbql1E%3D&pass_ticket=erLKJy9%2FjNsIg38TnEJDnS5SSSwutAhkHJKmf0wE6dmpC%2F961MRSiz2gWm61dmRM

序列化作用:

  1. 序列化:把Java对象转换为字节序列。
  2. 反序列化:把字节序列恢复为原先的Java对象。

    而且序列化机制从某种意义上来说也弥补了平台化的一些差异,毕竟转换后的字节流可以在其他平台上进行反序列化来恢复对象。

java对象序列化

Java目前并没有一个关键字可以直接去定义一个所谓的“可持久化”对象。
对象的持久化和反持久化需要靠程序员在代码里手动显式地进行序列化和反序列化还原的动作。

举个例子,假如我们要对Student类对象序列化到一个名为student.txt的文本文件中,然后再通过文本文件反序列化成Student类对象:

代码

  1. Student类定义

     public class Student implements Serializable {
     private String name;
     private Integer age;
     private Integer score;
     
     @Override
     public String toString() {
         return "Student:" + '\n' +
         "name = " + this.name + '\n' +
         "age = " + this.age + '\n' +
         "score = " + this.score + '\n'
         ;
     }
    
  2. 序列化

     public static void serialize(  ) throws IOException {
    
     Student student = new Student();
     student.setName("CodeSheep");
     student.setAge( 18 );
     student.setScore( 1000 );
    
     ObjectOutputStream objectOutputStream = 
         new ObjectOutputStream( new FileOutputStream( new File("student.txt") ) );
     objectOutputStream.writeObject( student );
     objectOutputStream.close();
     
     System.out.println("序列化成功!已经生成student.txt文件");
     System.out.println("==============================================");
    

    }

  3. 反序列化

     public static void deserialize(  ) throws IOException, ClassNotFoundException {
     ObjectInputStream objectInputStream = 
         new ObjectInputStream( new FileInputStream( new File("student.txt") ) );
     Student student = (Student) objectInputStream.readObject();
     objectInputStream.close();
     
     System.out.println("反序列化结果为:");
     System.out.println( student );
    

    }

  4. 运行结果

     序列化成功!已经生成student.txt文件
     ==============================================
     反序列化结果为:
     Student:
     name = CodeSheep
     age = 18
     score = 1000
    

Serializable接口作用

上面在定义Student类时,实现了一个Serializable接口,然而当我们点进Serializable接口内部查看,发现它竟然是一个空接口,并没有包含任何方法!


如果上面在定义Student类时忘了加implements Serializable时会发生什么呢?
实验结果是:此时的程序运行会报错,并抛出NotSerializableException异常:


我们按照错误提示,由源码一直跟到ObjectOutputStream的writeObject0()方法底层一看,才恍然大悟:


如果一个对象既不是字符串、数组、枚举,而且也没有实现Serializable接口的话,在序列化时就会抛出NotSerializableException异常!
原来Serializable接口也仅仅只是做一个标记用!!!
它告诉代码只要是实现了Serializable接口的类都是可以被序列化的!然而真正的序列化动作不需要靠它完成。

serialVersionUID号作用

private static final long serialVersionUID = -4392658638228508589L;

我们首先还是调用上面的serialize()方法,将一个Student对象序列化到本地磁盘上的student.txt文件:


接下来我们在Student类里面动点手脚,比如在里面再增加一个名为studentID的字段,表示学生学号:


这时候,我们拿刚才已经序列化到本地的student.txt文件,还用如下代码进行反序列化,试图还原出刚才那个Student对象:


运行发现报错了,并且抛出了InvalidClassException异常:


这地方提示的信息非常明确了:序列化前后的serialVersionUID号码不兼容!
从这地方最起码可以得出两个重要信息:

  • serialVersionUID是序列化前后的唯一标识符
  • 默认如果没有人为显式定义过serialVersionUID,那编译器会为它自动声明一个!

1、 第1个问题: serialVersionUID序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。

2、 第2个问题: 如果在定义一个可序列化的类时,没有人为显式地给它定义一个serialVersionUID的话,则Java运行时环境会根据该类的各方面信息自动地为它生成一个默认的serialVersionUID,一旦像上面一样更改了类的结构或者信息,则类的serialVersionUID也会跟着变化!

所以,为了serialVersionUID的确定性,写代码时还是建议,凡是implements Serializable的类,都最好人为显式地为它声明一个serialVersionUID明确值!
当然,如果不想手动赋值,你也可以借助IDE的自动添加功能,比如我使用的IntelliJ IDEA,按alt + enter就可以为类自动生成和添加serialVersionUID字段,十分方便:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值