您的位置:首页 > 产品设计 > UI/UE

Java对象的serialVersionUID在序列化和反序列化的用途

2016-09-29 12:44 926 查看
本博客主要转自如下链接
http://blog.csdn.net/javazejian/article/details/52665164
这篇文章写的不错,但是有些地方我估计博主没有亲自测试,所以有些地方我亲测后发现其实他说的不对,大家可以先看看他写的,然后再看看我下面说的具体哪里不对了

先说说serialVersionUID的用途:

其实一个类要实现序列化和反序列化,不声明serialVersionUID是可行的,serialVersionUID主要是辅助序列化和反序列化,序列化和反序列化的时候,serialVersionUID必须一致,反序列化才会成功。具体的序列化过程是这样的:序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。报出如下UID错误:

Exception in thread "main" java.io.InvalidClassException: com.zejian.test.Client;
local class incompatible: stream classdesc serialVersionUID = -2083503801443301445,
local class serialVersionUID = -4083503801443301445


原博文中主要错在这句话  “因此强烈建议指定serialVersionUID,这样的话即使微小的变化也不会导致crash的出现,如果不指定的话只要这个文件多一个空格,系统自动生成的UID就会截然不同的,反序列化也就会失败

亲测发现,当不指定serialVersionUID的时候,将对象序列化到文件中后,如果仅仅在对象文件中添加了一些空格或者换行,反序列化仍然会成功,而并不是那篇博客中说的加个空格就会反序列化失败。原因应该是serialVersionUID的生成方法是基于对象的一些属性生成的,而跟这个对象文件中的空格换行等是没有关系的。

我试着在没有指定的serialVersionUID的情况下,序列化后,在对象中添加了一个属性,并对之前生成的序列化后的文件进行反序列化,发现失败了,抛了上述说的异常,这是因为在对象中添加了属性后,由于没有指定serialVersionUID,所以系统会自动根据这个对象的属性等产生一个新的serialVersionUID,这就导致这个serialVersionUID与序列化文件中的serialVersionUID不一致,从而反序列化失败。

接着,我为对象加了serialVersionUID属性,在intellij
idea中为一个对象加serialVersionUID的方法如下:

Setting->Inspections->Serialization issues->Serializable class without ’serialVersionUID’
选中以上后,在你的class中:光标定位在类名前,按 Alt+Enter 就会提示自动创建 serialVersionUID 了。
在添加了serialVersionUID的对象中,我重新进行了序列化,序列化后,我在对象中添加了一个新的属性,也修改了原有的属性,但是serialVersionUID没有变,所以序列化文件中的serialVersionUID和对象文件中的serialVersionUID一致,反序列化都成功,但是只会反序列化成功匹配上的属性值,没有匹配上的都会为null。如果在序列化后修改了serialVersionUID的值,则反序列化会失败,抛出上述异常。

下面是上述博客中测试的例子,我进行了点修改方便测试:

被序列化对象Client:注意,这个对象中的几个object相关方法是用来自定义序列化和反序列化过程的,我们自定义哪些属性需要序列化,上述测试我把object相关方法都注释掉了。

package com.sogou.study.serialize;

/**
* Created by denglinjie on 2016/9/29.
*/
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;

public class Client implements Serializable{

/**
* 生成序列号标识
*/
private static final long serialVersionUID = -2083503801443301445L;

private int id;

private String name;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

/**
* 序列化时,
* 首先系统会先调用writeReplace方法,在这个阶段,
* 可以进行自己操作,将需要进行序列化的对象换成我们指定的对象.
* 一般很少重写该方法
* @return
* @throws ObjectStreamException
*/
private Object writeReplace() throws ObjectStreamException {
System.out.println("writeReplace invoked");
return this;
}
/**
*接着系统将调用writeObject方法,
* 来将对象中的属性一个个进行序列化,
* 我们可以在这个方法中控制住哪些属性需要序列化.
* 这里只序列化name属性
* @param out
* @throws IOException
*/
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
System.out.println("writeObject invoked");
//这里自定义只序列化了对象的name属性到文件中
out.writeObject(this.name == null ? "zejian" : this.name);
}

/**
* 反序列化时,系统会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,
* 反序列化回来.然后通过readResolve方法,我们也可以指定系统返回给我们特定的对象
* 可以不是writeReplace序列化时的对象,可以指定其他对象.
* @param in
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
System.out.println("readObject invoked");
//由于序列化的时候自定义只序列化了name属性,所以这里读出来的object就是name的值,可以直接转换成String
this.name = (String) in.readObject();
System.out.println("got name:" + name);
}

/**
* 通过readResolve方法,我们也可以指定系统返回给我们特定的对象
* 可以不是writeReplace序列化时的对象,可以指定其他对象.
* 一般很少重写该方法
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException {
System.out.println("readResolve invoked");
return this;
}
}


序列化类

package com.sogou.study.serialize;

/**
* Created by denglinjie on 2016/9/29.
*/

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeTest {

public static void main(String[] args) throws Exception {

//把对象序列化到文件
Client client = new Client();
client.setId(11);
client.setName("client");

ObjectOutputStream oo = new ObjectOutputStream
(new FileOutputStream("D:\\test\\file1.txt"));
oo.writeObject(client);
oo.close();
}
}


反序列化类:

package com.sogou.study.serialize;

/**
* Created by denglinjie on 2016/9/29.
*/

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class UnSerializeTest {

public static void main(String[] args) throws Exception {
//反序列化到内存
ObjectInputStream oi = new ObjectInputStream
(new FileInputStream("D:\\test\\file1.txt"));
Client c_back = (Client) oi.readObject();
System.out.println(c_back.getName());
System.out.println(c_back.getId());
oi.close();

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: