知识点:
1)序列化概念
2)实现序列化手段
3)序列化实现深克隆
4)主流序列化手段及操作
Java的序列化机制 Sericalize接口 存在的问题
1)序列化数据结果比较大 传输效率低
2)不能跨语言对接
后续xml编码格式的对象序列化机制成为了主流。
1)多语言
2)便于理解
Json
HTTP RESTful
基于二进制序列化框架 MessagePack
使用恰当的序列化协议不仅可以提高系统的通用性,强壮性,安全性,优化性能,同时能让系统更加易于调试和扩展。
把对象转化为字节序列的过程称为对象的序列化,反之就是对象的反序列化。
1)实现一个序列化操作 首先定义一个对象的类【实现序列化操作需要继承sericalize接口】
package com.llf.sericalizeTest;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = -8102469415223443135L;
private String Name;
private int age;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
复制代码
写一个测试类,首先我们提供序列化它的方法
然后执行能在相应的地方发现这个person文件生成
然后我们增加其反序列化的操作,并且把文件中反序列化对象中的我们赋值的拿出来
package com.llf.sericalizeTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SericalizeDemo {
public static void main(String[] args) {
//序列化操作
SericalizePerson();
//反序列化操作
DeSericalizePerson();
}
/**
* 序列化Person类
*/
private static void SericalizePerson(){
try {
//生成序列化二进制文件的地址
ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(new File("person")));
Person person=new Person();
person.setName("CQ");
person.setAge(18);
os.writeObject(person);
System.out.println("序列化成功!");
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void DeSericalizePerson(){
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("person")));
try {
Person person=(Person) ois.readObject();
System.out.println("名字叫 "+person.getName());
System.out.println("年龄是 "+person.getAge());
System.out.println("反序列化成功!");
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
ObjectInputStream :读取指定的字节数据转化为对象
serialVesionUID 的作用: 1)保证序列化对象和反序列化对象是同一个 序列化会有个版本号,如果没有这个的话,会生成新的。 2)静态变量的序列化
序列化不保存静态变量状态
序列化之后然后修改一个静态变量的值然后在反序列化发现对象的值已经变成修改后的值。
Transient 关键字
修饰的属性不参与序列化
序列化的父子类问题:
如果父类没有实现序列化,而子类实现序列化,那么父类中的成员没办法做序列化操作。
序列化的存储规则:
对同个对象进行多次写入,打印出的第一次存储结果和第二次存储结果只多了5个字节的引用关系,不会导致文件累加。
序列化实现深度克隆
1)浅克隆 :复制对象,不复制对象的引用
2)深克隆 :复制对象,复制对象的引用
序列化实现深克隆
package com.llf.sericalizeClone;
import java.io.Serializable;
public class Teacher implements Serializable{
/**
*
*/
private static final long serialVersionUID = -6957411933291636976L;
private String Name;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
@Override
public String toString() {
return "Teacher [Name=" + Name + "]";
}
}
复制代码
package com.llf.sericalizeClone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = -6029082021501636342L;
private String Name;
private int age;
private Teacher teacher;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public Object deapClone(){
ByteArrayOutputStream os=new ByteArrayOutputStream();
ObjectOutputStream oos=null;
ByteArrayInputStream is=null;
ObjectInputStream ois = null;
try {
//序列化
oos=new ObjectOutputStream(os);
oos.writeObject(this);
//反序列化
is=new ByteArrayInputStream(os.toByteArray());
ois=new ObjectInputStream(is);
try {
return ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
ois.close();
is.close();
oos.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String toString() {
return "Student [Name=" + Name + ", age=" + age + "]";
}
}
复制代码
package com.llf.sericalizeClone;
public class CloneDemo {
public static void main(String[] args) {
Teacher teacher=new Teacher();
teacher.setName("LLF");
Student student=new Student();
student.setName("CQ");
student.setAge(18);
student.setTeacher(teacher);
Student student2=(Student) student.deapClone();//克隆一个对象
System.out.println(student);
System.out.println(student2);
}
}
复制代码
总结: 1)在java中,只要一个类实现了java.io.serializable接口,那么她就可以被序列化
2) 通过objectoutputstream和objectinputstream对对象进行序列化和反序列化
3)对象是否被反序列化,不仅取决于对象的代码是否一致,同样还有一个重要因素(UID)
4)序列化不保存静态变量
5)要想父类对象也参与序列化操作,必须要让父类也实现serializable接口
6)Transient主要是控制控制变量是否能被序列化。如果没有被序列化的成员变量反序列化后会被设置为初始值。
7)通过序列化操作实现深度克隆。
当前主流的序列化技术有哪些
JSON
Hessian(2)
xml
protobuf
kryo
msgpack
FST
thrify
protostuff
avro
演示几种序列化手段的demo
首先是JSON
1)JSON
首先pom文件中引入jar包
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
复制代码
然后代码
package com.llf.serialiableJSON;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import com.llf.sericalizeTest.Person;
public class JsonDemo {
//初始化对象
private static Person init(){
Person person=new Person();
person.setName("张三");
person.setAge(18);
return person;
}
public static void main(String[] args) {
executeWithJackson();
}
@SuppressWarnings("unused")
private static void executeWithJackson(){
Person person=init();
ObjectMapper mapper=new ObjectMapper();
byte[] writeBytes=null;
long start=System.currentTimeMillis();
for(int i=0;i<100;i++){
try {
//序列化
writeBytes=mapper.writeValueAsBytes(person);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("JSON 序列化 "+(System.currentTimeMillis()-start)+"ms : 总大小为-->"+writeBytes.length);
//反序列化
try {
Person person2=mapper.readValue(writeBytes, Person.class);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
同样的阿里也是实现了一个jar包 fastjar
我们比较下俩者的耗时 遍历10万次以下是jackson快而10万以上是fastjson快。
package com.llf.serialiableJSON;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import com.alibaba.fastjson.JSON;
import com.llf.sericalizeTest.Person;
public class JsonDemo {
//初始化对象
private static Person init(){
Person person=new Person();
person.setName("张三");
person.setAge(18);
return person;
}
public static void main(String[] args) {
executeWithJackson();
executeWithFastJson();
}
@SuppressWarnings("unused")
private static void executeWithJackson(){
Person person=init();
ObjectMapper mapper=new ObjectMapper();
byte[] writeBytes=null;
long start=System.currentTimeMillis();
for(int i=0;i<100000;i++){
try {
//序列化
writeBytes=mapper.writeValueAsBytes(person);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("jackson JSON 序列化 "+(System.currentTimeMillis()-start)+"ms : 总大小为-->"+writeBytes.length);
//反序列化
try {
Person person2=mapper.readValue(writeBytes, Person.class);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void executeWithFastJson(){
Person person=init();
String text=null;
long start=System.currentTimeMillis();
for(int i=0;i<100000;i++){
//序列化
text=JSON.toJSONString(person);
}
System.out.println("fastjson JSON 序列化 "+(System.currentTimeMillis()-start)+
"ms : 总大小为-->"+text.getBytes().length);
//反序列化
Person person2=JSON.parseObject(text, Person.class);
}
}
复制代码
首先引入jar包,这是百度开发的一个jar包
<dependency>
<groupId>com.baidu</groupId>
<artifactId>jprotobuf</artifactId>
<version>2.1.2</version>
</dependency>
复制代码
我们先定义注解
然后序列化和反序列化
protobuf优势就是字节数少,非常适合网络传输。
hessian 序列化 定义方法
字节比较多,但是耗时很低我们看下各个序列化手段的耗时和字节对比
package com.llf.sericalizeTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SericalizeDemo {
public static void main(String[] args) {
//序列化操作
SericalizePerson();
//反序列化操作
DeSericalizePerson();
}
/**
* 序列化Person类
*/
private static void SericalizePerson(){
try {
//生成序列化二进制文件的地址
ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(new File("person")));
Person person=new Person();
person.setName("CQ");
person.setAge(18);
os.writeObject(person);
System.out.println("序列化成功!");
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void DeSericalizePerson(){
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("person")));
try {
Person person=(Person) ois.readObject();
System.out.println("名字叫 "+person.getName());
System.out.println("年龄是 "+person.getAge());
System.out.println("反序列化成功!");
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码