java序列化

       先说一下,前端时间做项目的时候,遇到一个需求就是需要定时去扫描一张表,并且将没有扫描过的数据在另一张表中进行操作,所以需要记住上一次扫描的主键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>
















              

            















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值