java的序列化机制支持将对象序列化为本地文件或者通过网络传输至别处, 而反序列化则可以读取流中的数据, 并将其转换为java对象. 被序列化的类需要实现接口, 使用和进行对象的读写操作.
当然, java的序列化机制并非如此简单, 以下是个人总结的一些知识点:
1. 对象读取的顺序应该和写入的顺序一致, 而且读取的次数不能超过已写入对象的个数. 比如文件中仅仅存在2个对象, 就不能连续调用3次()方法, 除非调用了reset, skip等对流重新定位的方法.
2. java序列化机制针对的是对象, 而不是类. 因此只有非静态成员变量才会被序列化成二进制数据.
3. 使用关键字修饰的成员变量不会被序列化为二进制数据.
4. 将对象序列化为二进制数据, 将二进制数据反序列化为java对象, 这两个操作可能位于不同的应用中, 甚至也可能在不同的计算机上进行. 需要保证这两种场合下都有class文件, 在序列化处和反序列处的class文件需要完成一致, 包括包名.
5. 序列化ID的作用. 上面的类中定义了序列化ID: final long = 1L;
这是一个非强制定义的静态成员,如果不定义序列化IDjava 序列化 写入mysql java序列化机制, 那么会给出一个黄色的警告, 这个警告可以忽略.
考虑这样的情形: 类定义了序列化ID, 且序列化对象时的值为1, 而反序列化时的值不为1, 那么此时将无法反序列化成功. 所以序列化ID可以用来限制某些用户的反序列化.
6. 父类的序列化问题. 根据java的对象实例化机制可知, 创建一个子类对象的过程中, 会创建其父类对象, 反序列化也不例外. 如果一个类实现了接口, 而其父类却没有实现接口, 那么在反序列化时,虚拟机会调用父类的无参构造函数创建父类对象java 序列化 写入mysql, 因此反序列化后父类成员变量的值为调用无参构造函数之后的值. 如果父类既没有实现接口, 也不存在无参构造函数, 那么在反序列化时将发生程序错误.
假设存在一个没有实现接口的Male类:
Java代码
{
;
;
(){
}
(){
;
}
(){
this.name=name;
}
(){
;
}
(){
this.age=age;
}
@
(){
"Male[name="+name+",age="+age+"]";
}
}
Male的子类则实现了接口:
Java代码
{
;
(){
super();
this.=;
}
D(){
;
}
ID(){
this.=;
}
@
(){
"[="++"]";
}
}
则反序列化对象后, 其name和age属性都发生了改变:
Java代码
=(1);
.("");
.(24);
t=m((
"male.obj"));
out.();
out.close();
=((
"male.obj"));
nt=()in.();
.out.(.()+","+.()
+","+.());
程序的输出为:
name = null, age = 0, = 1
可见, 父类属性值都"丢失"了, name和age都是调用Male无参构造函数之后的值. 假设将Male类中的无参构造函数删除, 再加上一个有参的构造函数,在反序列化时将发生程序错误.
7. 自定义序列化和反序列化操作. 如果为了某些特殊需求, 需要自定义序列化和反序列化操作,只要重写实现了接口的类中的()和()方法即可java 序列化 写入mysql, 典型的应用场景是对密码之类的敏感成员进行加密:
Java代码
{
=1L;
e;
d;
(,){
this.=;
this.=;
}
(){
}
ct(t){
try{
=out.();
field.put("",);
.out.("加密前:="+);
//模拟加密
=+"1";
.out.("加密后:="+);
field.put("",);
out.();
}catch(){
e.();
}
}
t(){
try{
=in.();
=()field.get("","");
=()field.get("","");
.out.("读取的原始="+);
//模拟解密
=.(0,.()-1);
.out.("解密后的="+);
}catch(){
e.();
}
}
}
程序的输出为:
加密前: =
加密后: =
读取的原始 =
解密后的 =
User [=, =]
8. 重复存储问题. 如果将同一个对象多次写入文件, 会有怎样的结果?
Java代码
=("user.obj");
=("","");
t=m(("user.obj"));
out.(user);
.out.(file.());
//改变的值后再次将user对象存入文件
user.("min");
out.(user);
.out.(file.());
=(("user.obj"));
=(User)in.();
=(User)in.();
.out.(.());
.out.(.());
程序的输出结果为:
109
114
User [=, =]
User [=, =]
程序中调用了2次()方法, 且没有出现程序错误, 由此可知确实向文件中写入了2个对象. 第二次写入user对象时, 系统发现文件中已经存在user对象, 将不再存入user对象的内容, 只写入一个引用和一些控制信息, 所以第二次写入user对象后文件的大小增加的很少, 而且也没有发生改变.
9. 如果一个类中包含非基本数据类型的成员变量, 那么不仅类本身需要实现接口, 类中的非基本数据类型也需要实现接口. java的一些核心类, 如,
基本数据类型的包装类等都已经实现了接口, 使用的时候可以查看文档.
10. 对于包含集合型成员的类来说,不仅类本身需要现接口, 集合中所存储的元素也要实现接口.
那么集合类(List, Set, Map)到底有没有实现接口呢? 这是我疑惑的地方, 文档中并没有说明.可以确定的是,
只要集合中的元素是可序列化的, 序列化过程就不会出错.