1 序列化的原因
java序列化主要是為了跨平臺(tái),實(shí)現(xiàn)對(duì)象的一致性,可在不同的平臺(tái)上,保持自己原有的屬性和方法不變
2 序列化的作用
- 永久的保存對(duì)象數(shù)據(jù)(將對(duì)象數(shù)據(jù)保存在文件當(dāng)中,活著是磁盤中);
- 在網(wǎng)絡(luò)上傳送對(duì)象的字節(jié)序列
- 通過RMI傳輸對(duì)象(不懂,囧)
- 將對(duì)象數(shù)據(jù)在進(jìn)程之間進(jìn)行傳遞
3 序列化的實(shí)現(xiàn)方式
3.1 實(shí)現(xiàn)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;
}
}
測(cè)試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()));
}
/**
* 序列化對(duì)象
*
* @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對(duì)象序列化成功!");
oos.close();
}
/**
* 反序列化得到對(duì)象
*
* @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對(duì)象反序列化成功!");
return person;
}
}
首先查看序列化后的文件內(nèi)容:
運(yùn)行結(jié)果:
序列化成功后,會(huì)在當(dāng)前類文件目錄下生成一個(gè)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()));
}
通過文件,反序列化,結(jié)果是:
我們可以看見Person類里面有個(gè)serialVersionUID,這個(gè)serialVersionUID是用來干什么的?
首先我們修改一下serialVersionUID,運(yùn)行一下demo,看看結(jié)果:
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)
報(bào)了一個(gè)異常,說明反序列化失敗;
Java序列化機(jī)制會(huì)根據(jù)serialVersionUID作序列化版本比較,反序列化時(shí),如果發(fā)現(xiàn)序列化數(shù)據(jù)里面的serialVersionUID與model類的serialVersionUID不同,就會(huì)導(dǎo)致反序列化失敗,出現(xiàn)序列化版本不一致的異常;
當(dāng)實(shí)現(xiàn)Serializable接口的實(shí)體類沒有顯示定義serialVersionUID,serialVersionUID對(duì)類的詳細(xì)信息具有較高的敏感性,一個(gè)空格的修改就會(huì)導(dǎo)致serialVersionUID的變化,Java序列化機(jī)制會(huì)根據(jù)編譯器實(shí)現(xiàn)的不同可能千差萬別,這樣在反序列化過程可能會(huì)導(dǎo)致意外的 InvalidClassException;
為了保證serialVersionUID在不同java編譯器實(shí)現(xiàn)的一致性,為了實(shí)現(xiàn)序列化接口的實(shí)體能夠兼容先前版本,強(qiáng)烈建議顯示聲明serialVersionUID;
顯式地定義serialVersionUID有兩種用途:
- 在某些場(chǎng)合,希望類的不同版本對(duì)序列化兼容,因此需要確保類的不同版本具有相同的serialVersionUID;
- 在某些場(chǎng)合,不希望類的不同版本對(duì)序列化兼容,因此需要確保類的不同版本具有不同的serialVersionUID。
3.2 實(shí)現(xiàn)Parcelable接口
Parcelabel 的實(shí)現(xiàn),需要在類中添加一個(gè)靜態(tài)成員變量 CREATOR,這個(gè)變量需要繼承 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 把對(duì)象包裝成JSON字符串傳輸
4 序列化比較
1、在使用內(nèi)存的時(shí)候Parcelable比Serializable的性能高;
2、Serializable在序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC(內(nèi)存回收);
3、Parcelable不能使用在將對(duì)象存儲(chǔ)在磁盤上這種情況,因?yàn)樵谕饨绲淖兓翽arcelable不能很好的保證數(shù)據(jù)的持續(xù)性;