一、概述
Serializable
是Java
所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。使用Serializable
来实现序列化相当简单,只需要在类的声明中指定一个类似下面的标识即可自动实现默认的序列化过程。
private static final long serialVersionUID = -499137596716953701L;
在Android
中还提供了新的序列化方法:Parcelable
接口,关于Parcelable
可以跳转到我的另一篇文章:。本文仅对Serializable
接口进行介绍。
实际上,想要一个对象可以实现序列化,只需要让这个类实现Serializable
接口即可,甚至连上面的serialVersionUID
都不是必需的,如果不声明serialVersionUID
同样也可以实现序列化,但是将会对反序列化过程产生影响,原因在后面解释。下面先来看一个Demo
示例。
二、示例
首先定义一个User
类:
public class User implements Serializable {
private static final long serialVersionUID = -499137596716953701L;
public int userId;
public String userName;
public boolean isMale;
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", isMale=" + isMale +
'}';
}
}
通过Serializable
方式实现对象的序列化,实现起来非常简单,几乎所有工作都被系统自动完成了。我们只需要通过ObjectOutputStream
和ObjectInputStream
即可轻松实现,代码如下所示:
//序列化过程
User user = new User(0, "jake", true);
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
//反序列化过程
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User newUser = (User) in.readObject();
System.out.println(newUser);
in.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
输出结果:
User{userId=0, userName='jake', isMale=true}
三、serialVersionUID
下面来讲一下serialVersionUID
,serialVersionUID
是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID
只有和当前类的serialVersionUID
相同才能够正常地的被反序列化。serialVersionUID
的详细工作机制是这样的:序列化的时候系统会去检测文件中的serialVersionUID
,看它是否和当前类的serialVersionUID
一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变换,这时是无法正常反序列化的,因此会报如下错误:
java.io.InvalidClassException: serializable.User; local class incompatible: stream classdesc serialVersionUID = -499137596716953701, local class serialVersionUID = -499137596716953702
一般来说,我们应该手动指定serialVersionUID
的值,比如1L
,也可以通过编译器自动生成,笔者使用的是IDEA
,默认情况下是不会提示生成serialVersionUID
的,需要在settings
中设置,如下图所示:

设置完成后,没有设置实现了
serializable
接口的类如果没有设置serialVersionUID
将会报警告。
不管是手动设置还是通过工具去生成,本质上没有区别,需要注意的是,静态成员变量属于类不属于对象,所以不参与序列化过程。其次用transient
关键字标记的成员变量不参与序列化过程。
另外,系统默认序列化过程也是可以改变的,通过实现如下两个方法即可重写系统默认的序列化和反序列化过程,不过大部分情况下我们不需要重写这两个方法。
private void readObject(ObjectInputStream in) throws IOException {
}
private void writeObject(ObjectOutputStream outputStream) throws IOException, ClassNotFoundException {
}
网友评论