Java序列化(Serializable)與反序列化詳解
什麼是序列化?
Java序列化是在JDK 1.1中引入的,是Java核心的重要特性之一。Java序列化API允許我們將一個物件轉換為流,並通過網路傳送,或將其存入檔案或資料庫以便未來使用,
反序列化則是將物件流轉換為實際程式中使用的Java物件的過程。
序列化有啥用?
1.暫存大物件2.Java物件需要持久化的時候
3.需要在網路,例如socket中傳輸Java物件
因為資料只能夠以二進位制的形式在網路中進行傳輸,因此當把物件通過網路傳送出去之前需要先序列化成二進位制資料,在接收 端讀到二進位制資料之後反序列化成Java物件
4.深度克隆(複製)
5.跨虛擬機器通訊
程式碼怎麼寫?
1.序列化例子
實體類:Student.java
package com.dylan.serialization;
import java.io.Serializable;
/**
* 學生類
*
* @author xusucheng
* @create 2018-01-08
**/
public class Student implements Serializable {
private int id;
private String name;
private String gender;
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Student(int id, String name, String gender) {
this.id = id;
this.name = name;
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
package com.dylan.serialization;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 序列化例子
*
* @author xusucheng
* @create 2018-01-08
**/
public class SerializationDemo {
public static void main(String[] args) throws IOException{
//學生1
Student s1 = new Student(101,"Jack","Male");
//學生2
Student s2 = new Student(102,"Lily","Female");
List<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
//建立檔案流
FileOutputStream fos = new FileOutputStream("D:\\test\\student01.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(list);
os.close();
System.out.println("序列化完成!");
}
}
2.反序列化例子
package com.dylan.serialization;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 反序列化例子
*
* @author xusucheng
* @create 2018-01-08
**/
public class DeserializationDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\test\\student01.ser");
ObjectInputStream is = new ObjectInputStream(fis);
Object obj = null;
List<Student> list = new ArrayList<>();
try {
list = (List<Student>)is.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
is.close();
//遍歷list,輸出
for (Student student:list){
System.out.println(student.toString());
}
}
}
3.serialVersionUID的作用
可以看到上面序列化例子中的學生實體類只是實現了Serializable介面,假如我現在接到客戶需求,要調整Student類,增加學生年齡屬性,調整後如下:
public class Student implements Serializable {
private int id;
private String name;
private String gender;
private int age;
...
此時,我在去執行反序列化程式,結果報錯了:
啥玩意?就是說Stuent類調整後,其序列化版本ID發生了變化,java又是根據這個ID來判斷是不是同一個類。ID不一樣則無法反序列化!
事實上如果一個類沒有定義serialVersionUID,它會自動計算出來並分配給該類。當發生以下情況,這個ID就會改變:
- 在類中新增一些新的變數。
將變數從transient轉變為非tansient,對於序列化來說,就像是新加入了一個變數而已
將變數從靜態的轉變為非靜態的,對於序列化來說,就也像是新加入了一個變數而已
這個時候就需要我們手動指定這個serialVersionUID了,它告訴jvm,嗨,這個學生類我更新了一下,反序列化的時候記得儘量向後相容,別報錯。通常我們有以下幾種方式:
serialVersionUID生成方式:
1)直接寫固定的1L;
2)利用JDK自帶serialver命令:切到類路徑下
3)IDEA生成serialVersionUID
Intellij IDEA 預設沒啟用這個功能Preferences->Editor->Inspections->Serialization issues->Serializable class without serialVersionUID 勾上
應用之後就開啟了檢測功能
在你的class名前(一定是游標移動到類名前):按(mac:option+return)或者( win:Alt+Enter) 就會提示自動建立 serialVersionUID 了。
加上serialVersionUID後的實體類如下:
public class Student implements Serializable {
private static final long serialVersionUID = -2110227637642817458L;
private int id;
private String name;
private String gender;
private int age;
...
再次執行反序列化又恢復正常了:
Student{id=101, name='Jack', gender='Male'}
Student{id=102, name='Lily', gender='Female'}
在這裡有一個建議,如果沒有特殊需求,就是用預設的 1L 就可以,這樣可以確保程式碼一致時反序列化成功。
那麼隨機生成的序列化 ID 有什麼作用呢,有些時候,通過改變序列化 ID 可以用來限制某些使用者的使用。
4.static和transient屬性無法序列化
transient翻譯過來就是短暫的,瞬時的。如果在可序列化的類中某個成員變數加了這個修飾,則說明它只在jvm執行時才儲存值,序列化時不會儲存的。
為了證明這一點,我們調整一下Student類,加入1個靜態變數mess和1個transient變數password。調整後的類如下:
package com.dylan.serialization;
import java.io.Serializable;
/**
* 學生類
*
* @author xusucheng
* @create 2018-01-08
**/
public class Student implements Serializable {
private static final long serialVersionUID = -2110227637642817458L;
private static String mess="null";
private int id;
private String name;
private String gender;
private int age;
private transient String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Student(int id, String name, String gender) {
this.id = id;
this.name = name;
this.gender = gender;
mess = "something";
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", password='" + password + '\'' +
", mess='" + mess + '\'' +
'}';
}
}
再次執行序列化,反序列化後:
結論沒問題。
5.序列化實戰:Socket傳輸序列化物件例子
package com.dylan.serialization;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author xusucheng
* @create 2018-01-08
**/
public class Server {
public static void main(String[] args) {
//The client is used to handle connections with a client once a connection is
//established.
Socket client = null;
//The following two objects handles our Serialization operations, ObjectOutputStream
//writes an object to the stream. ObjectInputStream reads an object from the stream.
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
ServerSocket server = new ServerSocket(8888);
client = server.accept();
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
Student student = (Student) in.readObject();
System.out.println(student);
// close resources
out.close();
in.close();
client.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
package com.dylan.serialization;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* @author xusucheng
* @create 2018-01-08
**/
public class Client {
public static void main(String[] args) {
Socket client = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
client = new Socket("127.0.0.1", 8888);
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
Student student = new Student(991,"Dylan","Male");
out.writeObject(student);
out.flush();
out.close();
in.close();
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
}
說明:假如Student類沒有實現序列化介面,在執行Client程式時會報錯:
正如我們前面所講,網路只能傳輸二進位制資料,Java物件要想傳輸必須先序列化。
執行效果:
以上只是講解了一下序列化的常用知識點,還有些深入的部分,以後有空再總結。
相關文章
- Serializable詳解(1):程式碼驗證Java序列化與反序列化Java
- Serializable java序列化Java
- java的序列化SerializableJava
- 什麼是Java Serializable(序列化)Java
- Java的序列化與反序列化Java
- Java--序列化與反序列化Java
- java 序列化與反序列化例項Java
- Java安全基礎之Java序列化與反序列化Java
- 深入分析Java的序列化與反序列化Java
- 詳解電子表格中的json資料:序列化與反序列化JSON
- Java物件流與序列化Java物件
- Java序列化與反序列化(原生方式與Jackson方式)Java
- Java物件的序列化與反序列化-Json篇Java物件JSON
- 【Java基礎】序列化與反序列化深入分析Java
- 序列化Serializable和Parcelable的理解和區別
- Django序列化元件Serializers詳解Django元件
- Java的序列化和反序列化Java
- Java IO: 序列化與ObjectInputStream、ObjectOutputStreamJavaObject
- java序列化Java
- php中序列化與反序列化PHP
- c#序列化與反序列化概述C#
- .net序列化與反序列化總結
- 什麼是Java序列化,如何實現java序列化Java
- Java——transient and 序列化Java
- java物件序列化Java物件
- java的序列化Java
- java 物件序列化要序列化那些內容Java物件
- JavaScript 鏈式結構序列化詳解JavaScript
- Flutter中JSON序列化與反序列化FlutterJSON
- Django REST framework 序列化與反序列化(4)DjangoRESTFramework
- C# 序列化與反序列化jsonC#JSON
- Java物件的序列化和反序列化實踐Java物件
- 從java的序列化和反序列化說起Java
- 什麼是Java序列化?如何實現序列化?Java
- Java序列化和hessian序列化的區別Java
- Java單例模式與反射及序列化Java單例模式反射
- 一文帶你全面瞭解java物件的序列化和反序列化Java物件
- C# Json 序列化與反序列化一C#JSON