Java序列化與反序列化
- 交流或更多內容請關注我的公眾號:nezha_blog
- 我的技術部落格:nezha.github.io
當兩個程式在進行遠端通訊時,彼此可以傳送各種型別的資料。無論是何種型別的資料,都會以二進位制序列的形式在網路上傳送。傳送方需要把這個Java物件轉換為位元組序列,才能在網路上傳送;接收方則需要把位元組序列再恢復為Java物件。
現在主要的序列化方式主要是兩個種。一種是Java原生以流的方法進行的序列化,另外一種就是Json序列化方式。我這裡Json的序列化方式主要是以Jackson為例。
1. Java原生序列化
這種方式只能將支援 java.io.Serializable 介面的物件寫入流中。每個 serializable 物件的類都被編碼,編碼內容包括類名和類簽名、物件的欄位值和陣列值,以及從初始物件中引用的其他所有物件的閉包。
概念
- 序列化:把Java物件轉換為位元組序列的過程。
- 反序列化:把位元組序列恢復為Java物件的過程。
用途
- 把物件的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中;
- 在網路上傳送物件的位元組序列。
物件序列化
java.io.ObjectOutputStream代表物件輸出流,它的writeObject(Object obj)方法可對引數指定的obj物件進行序列化,把得到的位元組序列寫到一個目標輸出流中。只有實現了Serializable和Externalizable介面的類的物件才能被序列化。
java.io.ObjectInputStream代表物件輸入流,它的readObject()方法從一個源輸入流中讀取位元組序列,再把它們反序列化為一個物件,並將其返回。
- 示例程式碼
import java.io.*;
import java.util.Date;
public class ObjectSaver {
public static void main(String[] args) throws Exception {
/*其中的 ./objectFile.obj 表示存放序列化物件的檔案*/
//序列化物件
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./objectFile.obj"));
Customer customer = new Customer("王麻子", 24);
out.writeObject("你好!"); //寫入字面值常量
out.writeObject(new Date()); //寫入匿名Date物件
out.writeObject(customer); //寫入customer物件
out.close();
//反序列化物件
ObjectInputStream in = new ObjectInputStream(new FileInputStream("./objectFile.obj"));
System.out.println("obj1 " + (String) in.readObject()); //讀取字面值常量
System.out.println("obj2 " + (Date) in.readObject()); //讀取匿名Date物件
Customer obj3 = (Customer) in.readObject(); //讀取customer物件
System.out.println("obj3 " + obj3);
in.close();
}
}
class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name=" + name + ", age=" + age;
}
}
複製程式碼
2. 使用Jackson序列化物件
準備工作:
ObjectMapper mapper = new ObjectMapper(); //轉換器
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
複製程式碼
將物件序列化
主要使用的是writeValueAsString
的函式
String json=mapper.writeValueAsString(user); //將物件轉換成json
複製程式碼
將Json字串物件化(反序列化)
主要使用的是readValue
的函式
Map m = mapper.readValue(json, Map.class);
複製程式碼
程式設計實現
- User類
public class User
{
private String id; //標識
private String name; //姓名
private int age; //年齡
private double pay; //工資
private boolean valid; //是否有效
private char one; //一個字元
@JsonFormat(pattern = "yyyy-mm-dd")
private Date birthday; //生日
private Link link; //聯絡方式,自定義
private Map map; //測試用
private List list; //測試用
private Set set; //測試用
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public double getPay()
{
return pay;
}
public void setPay(double pay)
{
this.pay = pay;
}
public boolean isValid()
{
return valid;
}
public void setValid(boolean valid)
{
this.valid = valid;
}
public char getOne()
{
return one;
}
public void setOne(char one)
{
this.one = one;
}
public Date getBirthday()
{
return birthday;
}
public void setBirthday(Date birthday)
{
this.birthday = birthday;
}
public Link getLink()
{
return link;
}
public void setLink(Link link)
{
this.link = link;
}
public Map getMap()
{
return map;
}
public void setMap(Map map)
{
this.map = map;
}
public List getList()
{
return list;
}
public void setList(List list)
{
this.list = list;
}
public Set getSet()
{
return set;
}
public void setSet(Set set)
{
this.set = set;
}
}
複製程式碼
- Link類
public class Link
{
private String phone; //行動電話
private String address; //地址
private String qq; //QQ
public String getPhone()
{
return phone;
}
public void setPhone(String phone)
{
this.phone = phone;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public String getQq()
{
return qq;
}
public void setQq(String qq)
{
this.qq = qq;
}
}
複製程式碼
- 主函式
public class JacksonTest {
public static void main(String[] args) throws JsonGenerationException,JsonMappingException,IOException {
User user=new User();
user.setId("01");
user.setName("張三");
user.setAge(33);
user.setPay(6666.88);
user.setValid(true);
user.setOne('E');
user.setBirthday(new Date(20l*366*24*3600*1000)); //1990年
Link link = new Link();
link.setAddress("河南省濟源市");
link.setPhone("13899995555");
link.setQq("123456");
user.setLink(link);
Map map=new HashMap();
map.put("aa", "this is aa");
map.put("bb", "this is bb");
map.put("cc", "this is cc");
user.setMap(map);
List list=new ArrayList(){};
list.add("普洱");
list.add("大紅袍");
user.setList(list);
Set set=new HashSet();
set.add("籃球");
set.add("足球");
set.add("乒乓球");
user.setSet(set);
ObjectMapper mapper = new ObjectMapper(); //轉換器
//測試01:物件--json
String json=mapper.writeValueAsString(user); //將物件轉換成json
System.out.println(json);
/* 結果如下:
{"id":"01","name":"張三","age":33,"pay":6666.88,"valid":true,"one":"E","birthday":1465185448998,
"link":{"phone":"13899995555","address":"河南省濟源市","qq":"123456"},
"map":{"aa":"this is aa","bb":"this is bb","cc":"this is cc"},
"list":["普洱","大紅袍"],
"set":["乒乓球","足球","籃球"]}
注意點:(1) 日期--長整型 (2)List、Set均轉成陣列
*/
//測試02:json--map
Map m = mapper.readValue(json, Map.class); //json轉換成map
System.out.println("pay:"+m.get("pay").getClass().getName()); //java.lang.Double
System.out.println("valid:"+m.get("valid").getClass().getName()); //java.lang.Boolean
System.out.println("birthday:"+m.get("birthday").getClass().getName()); //java.lang.Long
System.out.println("link:"+m.get("link").getClass().getName()); //java.util.LinkedHashMap
System.out.println("map:"+m.get("map").getClass().getName()); //java.util.LinkedHashMap
System.out.println("list:"+m.get("list").getClass().getName()); //java.util.ArrayList
System.out.println("set:"+m.get("set").getClass().getName()); //java.util.ArrayList
/* 結果如下:
pay:java.lang.Double
valid:java.lang.Boolean
birthday:java.lang.Long
link:java.util.LinkedHashMap
map:java.util.LinkedHashMap
list:java.util.ArrayList
set:java.util.ArrayList
注意點:(1) 日期--長整型 (2)map、子物件均轉換成了LinkedHashMap (3)List、Set均轉成ArrayList
*/
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
//測試03:map--json
json=mapper.writeValueAsString(m); //map轉json
System.out.println(json); //與之前格式完全相同,說明經過map轉換後,資訊沒有丟失
//測試04:json--物件
User u=mapper.readValue(json, User.class); //json轉java物件。經測,轉成物件後,一切恢復正常
System.out.println("pay:"+u.getPay());
System.out.println("valid:"+u.isValid());
System.out.println("birthday:"+u.getBirthday());
System.out.println("link:"+u.getLink().getAddress());
System.out.println("map:"+u.getMap());
System.out.println("list:"+u.getList());
System.out.println("set:"+u.getSet());
//測試05:其他轉換
byte[] data=mapper.writeValueAsBytes(u); //物件轉成二進位制陣列
}
}
複製程式碼