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

image.png

Java序列化与反序列化

微信公众号

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个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); //对象转成二进制数组
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,050评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,538评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,673评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,622评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,047评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,974评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,129评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,893评论 0 209
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,654评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,828评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,297评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,619评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,326评论 3 243
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,176评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,975评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,118评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,909评论 2 278

推荐阅读更多精彩内容