转自:https://blog.youkuaiyun.com/it_lihongmin/article/details/77932133
先说一下,前端时间做项目的时候,遇到一个需求就是需要定时去扫描一张表,并且将没有扫描过的数据在另一张表中进行操作,所以需要记住上一次扫描的主键ID,并且在重启服务后能不丢失。于是想到了序列化,但是没弄好,就采用了修改properties的方式(当然会有一个单利的类,对内存中的进行操作,提供效率)。
一、Java序列化
1、Java序列化: 把对象转化为字节序列的过程称为序列化,反之称为反序列化。
2、Java序列化的缺点:1)、结果为二进制文件,文件比较大,传输过程较长
2)、不能跨语言
3、serialVersionUID的作用,摘要算法生成一个唯一编号(类似于下载文件的MD5加密的作用)。
4、序列化的演进:
1)、由于java序列化的缺点很长一段时候都是使用xml进行对象的序列化,对语言进行兼容的同时,也比二进制的序列化容易理解。
即基于xml的soap协议对应的webservice很长一段时间成为标准。
2)、json的简单文本编码格式的Http restful 接口,但是json的问题在于序列化的的空间大、性能低等。
3)、为满足移动客户端的快速响应的体验,于是二进制协议成为热点,如:messagePack。
二、序列化的特点:
1、序列化不保存静态变量
2、transient:关键字修改的字段不参与序列化,则为其类型的默认值
3、如果父类没有序列化,而子类实现序列化,则子类中的父类成员不能进行序列化
4、序列化的存储规则:对同一对象进行多次写入,打印出的存储结果和第二次的存储结果,只是多了5个字节的引用关系,并不会累加文件。
- package com.kevin.demo;
- import java.io.Serializable;
- public class Person extends ParentPerson implements Serializable{
- /**
- *
- */
- private static final long serialVersionUID = -1410109129055379293L;
- private static String name;
- private String address;
- private transient int age;
- @Override
- public String toString() {
- return "Person [name=" + name + "address=" + address + ", age=" + age + "]";
- }
- public static String getName() {
- return name;
- }
- public static void setName(String name) {
- Person.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
- package com.kevin.demo;
- public class ParentPerson {
- private String oldName;
- public String getOldName() {
- return oldName;
- }
- public void setOldName(String oldName) {
- this.oldName = oldName;
- }
- }
- package com.kevin.demo;
- 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;
- /**
- * 序列化反序列化工具类
- * (如果写工具类可以考虑写的根目录的一个特定文件夹下,包名称的子文件夹下)
- * @author kevin
- *
- */
- public class SerializeUtil {
- public static void main(String[] args) {
- // 序列化对象
- // serialize();
- // 反序列化
- unSerialize();
- }
- /**
- * 序列化(将对象序列化到项目的根目录下)
- */
- public static void serialize(){
- try {
- ObjectOutputStream oStream = new ObjectOutputStream(new FileOutputStream(new File("person")));
- Person person = new Person();
- person.setName("kevin");
- person.setAge(18);
- person.setOldName("old kevin");
- person.setAddress("beijing");
- oStream.writeObject(person);
- System.out.println("序列化成功!");
- oStream.close();
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- public static void unSerialize(){
- try {
- ObjectInputStream iStream = new ObjectInputStream(new FileInputStream(new File("person")));
- Person person = (Person)iStream.readObject();
- System.out.println("反序列化成功!");
- System.out.println(person);
- iStream.close();
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- 反序列化成功!
- Person [name=nulladdress=beijing, age=0]
三、序列化实现深度克隆
1、浅拷贝(浅复制、浅克隆): 被复制对象的所以变量都有与原来的对象相同的值,而所有的其他对象的引用任然指向原来的对象。
2、深拷贝(深复制、深克隆):被复对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。即深拷贝,需要将对象引用的对象一并进行拷贝。
- public class Student implements Serializable{
- private static final long serialVersionUID = 5630895052908986144L;
- private String name;
- private int age;
- private Teacher teacher;
- 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 Teacher getTeacher() {
- return teacher;
- }
- public void setTeacher(Teacher teacher) {
- this.teacher = teacher;
- }
- public Object deepClone() throws IOException, ClassNotFoundException {
- //序列化
- ByteArrayOutputStream baos=new ByteArrayOutputStream();
- ObjectOutputStream oos=new ObjectOutputStream(baos);
- oos.writeObject(this);
- //反序列化
- ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
- ObjectInputStream ois=new ObjectInputStream(bais);
- return ois.readObject();
- }
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- ", teacher=" + teacher +
- '}';
- }
- }
- public class Teacher implements Serializable{
- private static final long serialVersionUID = -6635991328204468281L;
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return "Teacher{" +
- "name='" + name + '\'' +
- '}';
- }
- }
- public class CloneDemo {
- public static void main(String[] args) throws IOException, ClassNotFoundException {
- Teacher teacher=new Teacher();
- teacher.setName("mic");
- Student student=new Student();
- student.setName("kevin");
- student.setAge(18);
- student.setTeacher(teacher);
- Student student2=(Student) student.deepClone(); //
- System.out.println(student);
- student2.getTeacher().setName("james");
- System.out.println(student2);
- }
- }
四、主流的序列化技术及性能
JSON、 dubbo采用的 Hessian(2) 、xml、protobuf、kryo、MsgPack、FST、thrift、protostuff、Avro
用代码简单分析一下性能问题:
- public class JsonDemo {
- //初始化
- private static Person init(){
- Person person=new Person();
- person.setName("mic");
- person.setAge(18);
- return person;
- }
- public static void main(String[] args) throws IOException {
- // excuteWithJack();
- excuteWithFastJson();
- // excuteWithProtoBuf();
- //
- // excuteWithHessian();
- }
- private static void excuteWithJack() throws IOException {
- Person person=init();
- ObjectMapper mapper=new ObjectMapper();
- byte[] writeBytes=null;
- Long start=System.currentTimeMillis();
- for(int i=0;i<10000;i++){
- writeBytes=mapper.writeValueAsBytes(person);
- }
- System.out.println("Json序列化:"+(System.currentTimeMillis()-start)+"ms : " +
- "总大小->"+writeBytes.length);
- Person person1=mapper.readValue(writeBytes,Person.class);
- System.out.println(person1);
- }
- private static void excuteWithFastJson() throws IOException {
- Person person=init();
- String text=null;
- Long start=System.currentTimeMillis();
- for(int i=0;i<10000;i++){
- text=JSON.toJSONString(person);
- }
- System.out.println("fastjson序列化:"+(System.currentTimeMillis()-start)+"ms : " +
- "总大小->"+text.getBytes().length);
- Person person1=JSON.parseObject(text,Person.class);
- System.out.println(person1);
- }
- private static void excuteWithProtoBuf() throws IOException {
- Person person=init();
- Codec<Person> personCodec= ProtobufProxy.create(Person.class,false);
- Long start=System.currentTimeMillis();
- byte[] bytes=null;
- for(int i=0;i<10000;i++){
- bytes=personCodec.encode(person);
- }
- System.out.println("protobuf序列化:"+(System.currentTimeMillis()-start)+"ms : " +
- "总大小->"+bytes.length);
- Person person1=personCodec.decode(bytes);
- System.out.println(person1);
- }
- private static void excuteWithHessian() throws IOException {
- Person person=init();
- ByteArrayOutputStream os=new ByteArrayOutputStream();
- HessianOutput ho=new HessianOutput(os);
- Long start=System.currentTimeMillis();
- for(int i=0;i<10000;i++){
- ho.writeObject(person);
- if(i==0){
- System.out.println(os.toByteArray().length);
- }
- }
- System.out.println("Hessian序列化:"+(System.currentTimeMillis()-start)+"ms : " +
- "总大小->"+os.toByteArray().length);
- HessianInput hi=new HessianInput(new ByteArrayInputStream(os.toByteArray()));
- Person person1=(Person)hi.readObject();
- System.out.println(person1);
- }
- }
依赖的jar如下:
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-mapper-asl</artifactId>
- <version>1.9.13</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.31</version>
- </dependency>
- <dependency>
- <groupId>com.baidu</groupId>
- <artifactId>jprotobuf</artifactId>
- <version>2.1.2</version>
- </dependency>
- <dependency>
- <groupId>com.caucho</groupId>
- <artifactId>hessian</artifactId>
- <version>4.0.38</version>
- </dependency>
- </dependencies>