**
Java基础加强——序列化
**
1.何为对象序列化&反序列化
序列化和反序列化是java中进行数据存储和数据传输的一种方式.
1)对象序列化:将对象转换为字节或字符的过程。
2)对象反序列化:将字节或字符转换为对象的过程。
说明:在当前软件行业中有时也会将对象转换为字符串的过程理解为序列化,例如将对象转换为json格式的字符串。
2.序列化的应用场景
序列化和反序列化通常应用在:
1)网络通讯(C/S):以字节方式在网络中传输数据
2)数据存储(例如文件,缓存)
3.对象的序列化与反序列化实现
案例分析-01
1.定义一需要序列化的java类对象(用户行为日志对象)
class SysLog implements Serializable{
private static final long serialVersionUID = -5296788134693797316L;
/**日志id*/
private Integer id;
/**操作用户*/
private String username;
//private Date createdTime;
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "SysLog [id=" + id + ", username=" + username + "]";
}
}
2.定义测试类:
public class TestSerializable01 {
public static void main(String[] args)throws Exception {
//1.构建日志对象,并存储数据
SysLog log=new SysLog();
log.setId(1);
log.setUsername("tmooc");
//2.构建对象输出流,将日志对象存储到文件
ObjectOutputStream out=
new ObjectOutputStream(
new FileOutputStream("f1.data"));
out.writeObject(log);
//out.writeInt(100);//整数序列化
System.out.println("序列化ok");
out.close();
//3.将文件中的日志数据读出
ObjectInputStream in=
new ObjectInputStream(new FileInputStream("f1.data"));
SysLog obj=(SysLog)in.readObject();
//Integer result=in.readInt();//整数反序列化
//System.out.println(result);
in.close();
System.out.println(obj);
}
注:如果去掉序列化id,在增加一个成员,执行反序列化方法,报错,因为刚刚序列化的对象结构和反序列化的结构不一致了。然后添加序列化id,再执行反序列化方法,这时就不会报错啦。
所以:建议实现序列化接口的类自动生成一个序列化id.假如没有在类中显式添加此id,不会影响对象的序列化,但可能会对反序列化有影响(对象结构发生变化)。
4.序列化存在安全问题如何解决
java中的默认序列化是存在一些安全问题的,例如对象序列化以后的字节通过网络传输,有可能在网络中被截取。那如何保证数据安全呢?通常可以在对象序列化时对对象内容进行加密,对象反序列化时对内容进行解密。
具体实现过程分析:
1)在序列化对象中添加writeObject(ObjectOutpuStream out)方法
对内容进行加密再执行序列化。
2)在序列化对象中添加readObject(ObjectInputStream in)方法对
内容先进行反序列化然后在执行解密操作
class SysLog implements Serializable{
private static final long serialVersionUID = -5296788134693797316L;
/**日志id*/
private Integer id;
/**操作用户*/
private String username;
//private Date createdTime;
/**此方法会在调用对象流的的writeObject方法时执行*/
private void writeObject(ObjectOutputStream out) throws IOException{
//1.获取一个加密对象(java.util)
Base64.Encoder encoder=Base64.getEncoder();
//2.对内容进行加密
byte[] array=encoder.encode(username.getBytes());
//3.将加密结果重新赋值给username
username=new String(array);
//4.执行默认序列化
out.defaultWriteObject();//序列化
}//方法的声明是一种规范
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException{
//1.执行默认反序列化
in.defaultReadObject();
//2.获取解密对象
Base64.Decoder decoder=Base64.getDecoder();
//3.执行解密操作
byte[] array=decoder.decode(username);
username=new String(array);
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "SysLog [id=" + id + ", username=" + username + "]";
}
}
说明: writeObject/readObject方法:
1)访问修饰符,返回值类型,方法名,参数应与如上代码相同(java规范中定义)
2)两个方法会在序列化和反序列化时由系统底层通过反射调用.
5.序列化的粒度如何控制?
所谓序列化粒度一般指对象序列化时,如何控制对象属性的序列化。例如哪些序列化,哪些属性不序列化。java中的具体方案一般有两种:
方案1:不需要序列化的属性使用Transient修饰.
当少量属性不需要序列化时,使用此关键字修饰比较方便.例如 private transient Integer id;(例如arraylist,hashmap中的属性)
方案2:让序列化对象实现Externalizable接口,自己指定属性的序列化和反序列化过程, 但是要序列化的对象对应的类必须使用public修饰.
6.序列化的性能问题及如何优化?
Java中默认的序列化机制,其性能相对较差。此性能的提升,目前会借助一些第三方的框架进行实现,例如kryo ,其官方API应用网址.
(https://github.com/EsotericSoftware/kryo)。
总结:
序列化问题不再详细赘述,想要了解更详细的,可面向百度。部分内容摘自齐*的文档,在此向老师表达敬意。看过的小伙伴可以评论和支持哦!