Java的序列化与反序列化

说简单点,Java中反序列化最主要的作用就是创建一个对象

来,回顾下Java里面创建对象的四种方式:

  1. new关键字创建
  2. clone()方法创建
  3. 通过反射方式创建
  4. 反序列化(反串行化)创建

好了,清楚了。

既然反序列化是拿到一个对象,那么序列化其实是借助 I/O 流将我们的这个可序列化的类的信息存储起来 -> 永久的保存在磁盘上

借助到了 I/O 流,肯定是通过write方法写入文件,再用read方法读出文件中的数据,拿到这个类的一个对象。

好了,说一下具体的细节要点:

1、可序列化的类
一个普通的Java类是什么样子呢?就是那个样子,还能是啥。

可序列化的类长啥样子呢?☟
class Boy implements Serializable,可序列化的类实现了这么一个接口;这个接口是一个标识接口,表明实现了它的子类可以进行序列化。

标识接口Serializable

public interface Serializable {
}

里面啥也没有。

此外Java还有另一个比较重要的标识接口Cloneable

2、序列化ID

private static final long serialVersionUID = 2344444499999999999L;

就是这个东西。

为什么要有这个东西:我通过序列化将一个类保存起来,那我反序列化的时候,如何知道我拿到的就是我反序列化的对象呢。

当序列化ID跟反序列化ID一致时那就是了。

所以,第一点:要实现序列化的类中,可以给定一个long类型的ID,没给也没关系,系统会自动生成一个;

第二点:当这个序列化ID变化的时候,就会反序列化失败。常见错误包括

  • 序列化之后,改变了这个序列化ID的值
  • 序列化时,自己没提供;反序列化时,又加了一个序列化ID
  • 序列化时自己提供;反序列化时删掉了

3、序列化和反序化的实现

首先,一个实现了Serializable的类:

//类里面的其它信息我就不写了,也不重要
class Boy implements Serializable, Cloneable{
    //随便给定一个序列化ID
    private static final long serialVersionUID = 2344444499999999999L;
}

实现序列化和反序列化借助的类:
ObjectOutputStream、输出流、写入文件
ObjectInputStream、输入流、读文件内容

这里用的是writeObject()、readObject()

实现序列化

File file = new File("F:/Test/serialize.txt");
ObjectOutputStream outputStream  = new ObjectOutputStream(new FileOutputStream(file));
//写入这个对象
outputStream.writeObject(new Boy());
//写入一些信息
outputStream.writeObject(new Boy("tony", 22));
//再比如一个方法的内容(当前这个方法返回一个类的实例)
outputStream.writeObject(new Boy().getInstance());
outputStream.close();

实现反序列化

 ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
 //返回一个 Object 类型的实例
 Object o = inputStream.readObject();
 //也可以强转
 Boy boy = (Boy) inputStream.readObject(); 
 System.out.println(o);
 System.out.println(boy);
 inputStream.close();

输出:
在这里插入图片描述

本来我想说都可以,都是一样的。

上面序列化写入文件,保存了三个信息,它依次读取到了其中的前两个
也可以这么搞:

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
Boy tmp = null;
while ((tmp = (Boy) inputStream.readObject()) != null) {
    System.out.println(tmp);
}
inputStream.close();

输出:
在这里插入图片描述
还顺便抛了个异常出来,查了下,这个异常表明流读取到了末尾。我们主要使用序列化拿到一个对象,或者我们要保存起来的信息,所以不影响的~我主要是想试试把写入的对象都拿出来

还有:
Object o = inputStream.readObject();这样做,虽然也输出了,但是这算是一个父类,父类是拿不到子类的方法的:
在这里插入图片描述
Boy boy = (Boy) inputStream.readObject();强转才是王道:
在这里插入图片描述

4、transient关键字
用来修饰成员变量,在此次序列化中不被序列化。

我们实现序列化,就是将对象保存在文件中。同时也会将这个类中的其他东西保存。

如果我们有一个数组,只用了一部分,那么序列化的时候就会整个的序列化掉,是一种浪费;因此我们不让它序列化,就能够减少一些浪费。

5、序列化目的

  1. 永久保存对象在磁盘上
  2. 在网络中可以采用序列化机制直接传输对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值