文章目录
一、理解Java序列化和反序列化
Serialization(序列化):将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。
deserialization(反序列化):将保存在磁盘文件中的java字节码重新转换成java对象称为反序列化。
二、序列化和反序列化的应用
两个进程在远程通信时,可以发送多种数据,包括文本、图片、音频、视频等,这些数据都是以二进制序列的形式在网络上传输。
java是面向对象的开发方式,一切都是java对象,想要在网络中传输java对象,可以使用序列化和反序列化去实现,发送发需要将java对象转换为字节序列,然后在网络上传送,接收方收到字符序列后,会通过反序列化将字节序列恢复成java对象。
同时在Redis中如果使用默认的序列化器,那么存储到Redis的值将会是一堆杂乱无章的字符,这时我们可以手动设置序列化器
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
//默认的Key序列化器为:JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
java序列化的优点:
实现了数据的持久化,通过序列化可以把数据持久地保存在硬盘上(磁盘文件)。
利用序列化实现远程通信,在网络上传输字节序列。
三、序列化和反序列化地实现
JDK类库提供的序列化API:
java.io.ObjectOutputStream
表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。
java.io.ObjectInputStream
该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回。
序列化要求:
实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常。
四、serialVersionUID的作用
一句话:其目的是序列化对象版本控制,有关各版本反序列化时是否兼容。如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。
erialVersionUID有两种显示的生成方式:
一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,
五、静态变量的序列化
首先需要说一下,静态变量不会被序列化。因为静态变量在全局区,本来流里面就没有写入静态变量,我打印静态变量当然会去全局区查找,当我write read 同时使用时,内存中的静态变量变了。
六、Transient 关键字作用
Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
这个很好理解也很简单。下面代码来看一下他的作用
第一步:把User里面的年龄属性改成Transient 修饰。private transient int age;
第二步:Test不变,进行序列化和反序列化。
第三步:看结果。反序列化之后的输出age应该为0;