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不能很好的保證數據的持續性;