什么是序列化?
序列化可以保存我们实体类的状态,就是保存当前的类中属性的状态到硬盘中,保证下次或者在其他服务里可以接着使用这个类中的属性的时候,就是序列化。
序列化注意的点?
- 序列化只序列对象的属性,不管方法
- 静态类成员不序列化,因为静态属性是属于类的,我们序列化是针对目前的对象状态
- transient关键字修饰的属性不序列化
什么场景需要序列化?
- 需要对对象进行IO操作持久化
- Mybatis开启了二级缓存且配置文件中readOnly属性默认为false
- 在分布式系统中传递当前实体类对象
· 需要对对象进行IO操作持久化
首先我们来看代码示例:
实体类未实现序列化接口
package 实践类demo.为什么需要序列化.entity;
/**
* [简要描述]:
*
* @author zhihuan
* @version 2021/6/12 11:31
* @see 实践类demo.为什么需要序列化
*/
public class UserEntity {
private String username;
private String password;
private String nickname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public String toString() {
return "UserEntity{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
然后我们进行IO操作:
package 实践类demo.为什么需要序列化;
import org.omg.CORBA.portable.OutputStream;
import 实践类demo.为什么需要序列化.entity.UserEntity;
import java.io.*;
/**
* [简要描述]:
*
* @author zhihuan
* @version 2021/6/12 11:30
* @see 实践类demo
*/
public class IOStreamTest {
public static void main(String[] args) {
File file = new File("UserEntity.ser");
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
UserEntity userEntity = new UserEntity();
userEntity.setNickname("梅西");
userEntity.setUsername("messi");
userEntity.setPassword("77777777");
objectOutputStream.writeObject(userEntity);
objectOutputStream.close();
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
UserEntity tempUser =(UserEntity) objectInputStream.readObject();
System.out.println(tempUser.toString());
objectInputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
可以看到上面的将对象写入文件的时候就已经报没有序列化的异常了。
在实体类实现了序列化接口之后,就能执行成功!
· private static long serialVersionUID = 1L的意义?
Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。当实现java.io.Serializable接口的实体类没有显式地定义一个名为serialVersionUID,类型为long的变量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID 。
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化
· 为什么需要对对象进行IO操作持久化?
这里的话我在学习的时候又有了一个问题:为什么JAVA不直接让类可以被序列化,而是需要通过实现一个空接口的方式??这里看到一个合理的解释是:还是JAVA考虑到安全性的问题,如果没有一个标记让开发者可以控制序列化的实现,每个类都可以被序列化,那么一些对象的private属性就可以直接在序列化的文件中被看到,这在某些场景下还是被要求私密的。所以添加了一个这样的空接口让开发者自己决定序列化的问题。而这个空接口也仅仅就是标记实现了它的类可以被序列化
Mybatis开启了二级缓存且配置文件中readOnly属性默认为false
这个小标题其实就是针对Mybatis的场景这么起的,不具备概括性。
这里其实归根结底还是一个内存到硬盘的持久化过程,因为Mybatis中的缓存机制就是先把查询出来的内容放到内存中,然后内存不够了的话,就会把内存中的内容持久化到硬盘里,还是我们上面所说的一个需要一个序列化的必要。
在分布式系统中传递当前实体类对象
因为数据在网络中的传输都是二进制的,所以需要先将我们的对象序列化成为字节流传输过去,另一方接收到的时候再通过反序列化得出我们希望传递的那个状态的对象
问题1:那我不序列化,我转成JSON字符串可不可以啊?
当然是可以的,我们转成字符串,然后我们去瞧瞧Java里string的源码, string就是会实现了序列化接口的
问题2:我记得我平时一些VO类没有序列化过呀,怎么还是可以接收或者发送那些请求参数的?
这是因为那个场景下,我们不做特定的修改的话大部分情况下就是使用JSON序列化的方式。像JSON序列化我们还有熟悉的阿里提供的FastJson,谷歌的Gson,还有美团的MSON等众多转码的工具组件。我们这里讨论的只是java提供的序列化方式。这两个目前不要弄混了。
粗略的见解,如有错误请各位路过的大佬指出讨论–