1 序列化的原因
java序列化主要是为了跨平台,实现对象的一致性,可在不同的平台上,保持自己原有的属性和方法不变
2 序列化的作用
- 永久的保存对象数据(将对象数据保存在文件当中,活着是磁盘中);
- 在网络上传送对象的字节序列
- 通过RMI传输对象(不懂,囧)
- 将对象数据在进程之间进行传递
3 序列化的实现方式
3.1 实现Serializable接口
public class Person implements Serializable {
/**
* 序列化id
*/
private static final long serialVersionUID = 112347861234817234L;
private int age;
private String name;
private String sex;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
测试demo:
public class SerializableDemo {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
Person person = new Person();
person.setName("周杰伦");
person.setAge(36);
person.setSex("男");
serializablePerson(person);
Person newPerson = deSerializablePerson();
System.err.println(MessageFormat.format("name={0},age={1},sex={2}", newPerson.getName(), newPerson.getAge(),
newPerson.getSex()));
}
/**
* 序列化对象
*
* @param person
* @throws FileNotFoundException
* @throws IOException
*/
private static void serializablePerson(Person person) throws FileNotFoundException, IOException {
File file = new File("./person.txt");
if (!file.exists()) {
file.createNewFile();
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(person);
System.out.println("Person对象序列化成功!");
oos.close();
}
/**
* 反序列化得到对象
*
* @return
* @throws FileNotFoundException
* @throws IOException
* @throws ClassNotFoundException
*/
private static Person deSerializablePerson() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("./person.txt")));
Person person = (Person) ois.readObject();
System.out.println("Person对象反序列化成功!");
return person;
}
}
首先查看序列化后的文件内容:
运行结果:
序列化成功后,会在当前类文件目录下生成一个person.txt文件
注释掉序列化代码后:
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
// Person person = new Person();
// person.setName("周杰伦");
// person.setAge(36);
// person.setSex("男");
// serializablePerson(person);
Person newPerson = deSerializablePerson();
System.err.println(MessageFormat.format("name={0},age={1},sex={2}", newPerson.getName(), newPerson.getAge(),
newPerson.getSex()));
}
通过文件,反序列化,结果是:
我们可以看见Person类里面有个serialVersionUID,这个serialVersionUID是用来干什么的?
首先我们修改一下serialVersionUID,运行一下demo,看看结果:
Exception in thread "main" java.io.InvalidClassException: com.haizhi.Person; local class incompatible: stream classdesc serialVersionUID = 112347861234817234, local class serialVersionUID = 112347861234817235
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1622)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.haizhi.SerializableDemo.deSerializablePerson(SerializableDemo.java:55)
at com.haizhi.SerializableDemo.main(SerializableDemo.java:21)
报了一个异常,说明反序列化失败;
Java序列化机制会根据serialVersionUID作序列化版本比较,反序列化时,如果发现序列化数据里面的serialVersionUID与model类的serialVersionUID不同,就会导致反序列化失败,出现序列化版本不一致的异常;
当实现Serializable接口的实体类没有显示定义serialVersionUID,serialVersionUID对类的详细信息具有较高的敏感性,一个空格的修改就会导致serialVersionUID的变化,Java序列化机制会根据编译器实现的不同可能千差万别,这样在反序列化过程可能会导致意外的 InvalidClassException;
为了保证serialVersionUID在不同java编译器实现的一致性,为了实现序列化接口的实体能够兼容先前版本,强烈建议显示声明serialVersionUID;
显式地定义serialVersionUID有两种用途:
- 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
- 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
3.2 实现Parcelable接口
Parcelabel 的实现,需要在类中添加一个静态成员变量 CREATOR,这个变量需要继承 Parcelable.Creator 接口。
public class Student implements Parcelable{
private int name;
private String grade;
private int score;
public Students(Parcel source){
name = sourece.readString();
grade = source.readString();
score = source.readInt();
}
public int getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public int getScore(){
return score;
}
public void setScore(int score){
this.score = score;
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(name);
dest.writeString(grade);
dest.writeInt(score);
}
//Interface that must be implemented and provided as a public CREATOR field that generates instances of your Parcelable class from a Parcel.
public final static Parcelable.Creator<Students> CREATOR = new Parcelable.Creator<Students>() {
@Override
public Students createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new Students(source);
}
@Override
public Students[] newArray(int size) {
// TODO Auto-generated method stub
return new Students[size];
}
};
}
3.3 把对象包装成JSON字符串传输
4 序列化比较
1、在使用内存的时候Parcelable比Serializable的性能高;
2、Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC(内存回收);
3、Parcelable不能使用在将对象存储在磁盘上这种情况,因为在外界的变化下Parcelable不能很好的保证数据的持续性;