Java序列化與反序列化(原生方式與Jackson方式)

哪吒小子發表於2017-12-14

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); //物件轉成二進位制陣列
    }
}
複製程式碼

相關文章