java序列化截止 serialize接口
java本身序列化机制存在的问题
1 序列化数据结果比较大,效率比较低
2 不能跨语言对接
XML编码格式的对象序列化机制成为了主流
HTTP Restful
MessagePack
Protocol Buffers
Dubbo kryo
恰当的序列化机制,不仅可以提交系统的通用性,健壮性,安全性,优化性能,同时还能让系统更加易于调试和扩展。
序列化和反序列的概念
把对象转化为字节序列的过程,称之为序列化,反之就是反序列化。
怎么去实现一个序列化操作
ObjectInputStream readObject() :将二进制文件反序列化一个对象
ObjectOutputStream writeObject(persion):将对象序列化为二进制文件
实例代码
public class SerializeDemo {
public static void main(String[] args){
//序列化操作
seralizePersion();
//反序列化操作
deseralizePersion();
}
/**
* @Description: 反序列化
* @Author: ljj
* @CreateDate: 2019/5/31 11:20
* @UpdateUser:
* @UpdateDate:
* @UpdateReakem
* @param
* @Return: void
**/
private static void deseralizePersion(){
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("persion")));
Persion persion = (Persion) ois.readObject();
System.out.println(persion);
System.out.println("反序列化成功");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* @Description: 序列化
* @Author: ljj
* @CreateDate: 2019/5/31 11:20
* @UpdateUser:
* @UpdateDate:
* @UpdateReakem
* @param
* @Return: void
**/
private static void seralizePersion(){
try {
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("persion")));
Persion persion = new Persion();
persion.setAge("18");
persion.setName("张三丰");
oo.writeObject(persion);
System.out.println("序列化成功");
oo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
persion对象
package serializeStudy;
import java.io.Serializable;
/**
* @Description TODO
* @Author lijunjie
* @CreateDate 2019/5/31 10:17
* @UpdateUse
* @UpdateDate
* @UpdateRemark
* @版本 1.0
**/
public class Persion implements Serializable{
private static final long serialVersionUID = -4111090578350404098L;
private String name;
private String age;
public String getName() {
return name;
}
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public void setAge(String age) {
this.age = age;
}
}
序列化生成文件的位置
serialVersionUID有两种显示的生成方式:
一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = -4111090578350404098L;
serialVersionUID的作用:
1. 能够保证序列化的对象和反序列化的对象是同一个
静态变量的序列化
序列化并不保存静态变量的状态
persion类中有一个静态变量是sex,序列化是该值是“未知”,反序列化之前这个值被修改为了男,那么反序列化得到的对象的sex属性就是男;
序列化
反序列化
结果
transient 关键字
用transient修饰的属性不参与序列化。
比如序列化的对象属性如下
反序列之后的结果如下,transient修饰的属性的值会丢失。
子类实现了Serializable接口,而父类没有实现,子类对象调用父类的方法给父类属性设值,将子类对象进行序列化,反序列化值之后父类的属性值会丢失,因此,如果需要序列化的操作,那么父类和子类都需要实现Serializable接口
序列化的存储规则
对同一个对象进行多次写入,打印出的第一次存储结果,只是比第二次的存储结果多了5个字节的应用关系,并不会导致文件累加。
序列化实现深度克隆
浅克隆:复制对象,不复制对象的引用
深克隆:复制对象,并且复制对象的引用,也就是内存中的堆栈信息
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bos);
oo.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ios = new ObjectInputStream(bis);
return ios.readObject();
}
public class CloneDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Teacher teacher = new Teacher();
teacher.setName("张先生");
Student student = new Student();
student.setName("小明同学");
student.setAge(6);
student.setTeacher(teacher);
System.out.println(student);
Student student2 = (Student) student.deepClone();//克隆一个对象
teacher.setName("小红");
student2.setTeacher(teacher);
System.out.println(student);
System.out.println(student2);
}
}
总结:
1 在java中只要一个类实现了java.io.Serializeble接口,那么它就可以被序列化
2 通过ObjectOutputStream和ObjectInputStream对对象进行序列化和反序列化操作
3 对象是否允许被反序列化,不仅仅取决于对象的代码是否一致,同时还有一个重要的因素(UID)
4 序列化不保存静态变量
5 要想让父类对象也参与序列化,必须让父类也实现Seralizeble的接口
6 transient关键字主要控制变量是否参与序列化,如果成员变量被transient修饰,那么该成员变量反序列化之后被赋予初始值
7 通过序列化实现深度克隆
主流的序列化机制:
JSON/xml/Hessian(2)/protobuf/kryo/MsgPack/FST/thrift/prototuff/Arvo
Protobuf的优势:序列化时间更短,字节数更小
Hessian的序列化时间比Protobuf时间更短,缺点是字节数比较大
测试代码如下
package serializeStudy.json;
import com.alibaba.fastjson.JSON;
import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import org.codehaus.jackson.map.ObjectMapper;
import serializeStudy.Persion;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @Description TODO
* @Author lijunjie
* @CreateDate 2019/5/31 17:07
* @UpdateUse
* @UpdateDate
* @UpdateRemark
* @版本 1.0
**/
public class JsonDemo {
/**
* @Description: 初始化
* @Author: ljj
* @CreateDate: 2019/5/31 17:10
* @UpdateUser:
* @UpdateDate:
* @UpdateReakem
* @param
* @Return: serializeStudy.Persion
**/
private static Persion init(){
Persion persion = new Persion();
persion.setName("王学志");
persion.setAge("20");
return persion;
}
public static void main(String[] args) throws IOException {
excuteWithJackson();
excuteWithFastJson();
excuteWithProtobuf();
excuteWithHessian();
}
/**
* @Description: 属性即便有transient修饰,依然可以进行序列化
* @Author: ljj
* @CreateDate: 2019/6/3 10:55
* @UpdateUser:
* @UpdateDate:
* @UpdateReakem
* @param
* @Return: void
**/
private static void excuteWithJackson() throws IOException {
Persion persion = init();
ObjectMapper om = new ObjectMapper();
Long start = System.currentTimeMillis();
byte[] writeBytes = null;
for(int i = 0;i<10000;i++){
writeBytes = om.writeValueAsBytes(persion);
}
Long end = System.currentTimeMillis();
System.out.println("Jackson序列化的时间"+(end-start)+"ms 序列化之后的大小"+writeBytes.length);
Persion persion1 = om.readValue(writeBytes,Persion.class);
System.out.println(persion1);
}
public static void excuteWithFastJson(){
Persion persion = init();
String text = null;
Long start = System.currentTimeMillis();
for(int i = 0;i<10000;i++){
text = JSON.toJSONString(persion);
}
Long end = System.currentTimeMillis();
System.out.println("fastjson序列化的时间"+(end-start)+"ms 序列化之后的大小"+text.length());
Persion persion1 = JSON.parseObject(text,Persion.class);
System.out.println(persion1);
}
public static void excuteWithProtobuf() throws IOException {
Persion persion = init();
Codec<Persion> persionCodec = ProtobufProxy.create(Persion.class,false);
Long start = System.currentTimeMillis();
byte[] bytes = null;
for(int i = 0;i<10000;i++){
bytes = persionCodec.encode(persion);
}
Long end = System.currentTimeMillis();
System.out.println("Protobuf序列化的时间"+(end-start)+"ms 序列化之后的大小"+bytes.length);
Persion persion1 = persionCodec.decode(bytes);
System.out.println(persion1);
}
public static void excuteWithHessian() throws IOException {
Persion persion = init();
ByteArrayOutputStream os = new ByteArrayOutputStream();
HessianOutput ho = new HessianOutput(os);
Long start = System.currentTimeMillis();
byte[] bytes = null;
int temp = 0;
for(int i = 0;i<10000;i++){
ho.writeObject(persion);
if(i == 0){
temp=os.toByteArray().length;
}
}
Long end = System.currentTimeMillis();
System.out.println("hessian序列化的时间"+(end-start)+"ms 序列化之后的大小"+temp);
HessianInput hi =new HessianInput(new ByteArrayInputStream(os.toByteArray()));
Persion persion1 = (Persion) hi.readObject();
System.out.println(persion1);
}
}
测试结果:
pom文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>serializeStudy</groupId>
<artifactId>serializeStudy</artifactId>
<version>1.0-SNAPSHOT</version>
<name>serializeStudy</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baidu/jprotobuf -->
<dependency>
<groupId>com.baidu</groupId>
<artifactId>jprotobuf</artifactId>
<version>2.2.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.7</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
需要注释的是,使用jprotobuf 时,实体类上面需要注解
package serializeStudy;
import com.baidu.bjf.remoting.protobuf.FieldType;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
import java.beans.Transient;
import java.io.Serializable;
/**
* @Description TODO
* @Author lijunjie
* @CreateDate 2019/5/31 10:17
* @UpdateUse
* @UpdateDate
* @UpdateRemark
* @版本 1.0
**/
public class Persion implements Serializable{
private static final long serialVersionUID = -4481771669565645999L;
@Protobuf(fieldType = FieldType.STRING)
private String name;
@Protobuf(fieldType = FieldType.STRING)
private String age;
private static String sex = "未知";
public static String getSex() {
return sex;
}
public static void setSex(String sex) {
Persion.sex = sex;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", sex='" + sex + '\'' +
'}';
}
public void setAge(String age) {
this.age = age;
}
}