Java序列化与反序列化
- 交流或更多内容请关注我的公众号:nezha_blog
- 我的技术博客:https://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); //对象转成二进制数组
}
}