什么是Java对象序列化?
Java中的序列化主要是指对Java对象的序列化。Java对象的序列化就是把Java对象转换成跟平台无关的二进制流,反序列化就是把序列化的二进制流恢复成原来的JAVA对象。
为什么要进行序列化?
当虚拟机停止运行之后,内存中的对象就会消失,Java对象经过序列化可以将对象转换成二进制流保存下来,比如保存在磁盘中,一般是保存到文件中,或者将对象的序列化为字符串保存到数据库中,然后在需要读取对象情况的时候反序列化为对象。可以对序列化后的对象进行读写操作。
java对象进行远程传输的时候需要序列化,对象序列化之后可以将通过流的方式在网络上传输。
怎样实现对象的序列化?
被序列化的类需要首先实现Serializable接口,然后再使用ObjectOutputStream对象输出流的writeObject(Object obj)方法将参数obj的对象序列化写出,把得到的字节序列写到一个目标输出流中;使用ObjectIntputStream对象输入流的readObject( )方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
序列化的时候需要注意什么?
这里有几个原则,我们一起来看下:
1、Serializable接口是一个标示性接口,接口中没有定义任何的方法或字段,因此没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。
2、静态变量和成员方法不可序列化,就是只对对象的状态进行保存,而不管对象的方法。
3、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;前提是该类中的所有引用对象也必须是可以被序列化的。否则整个序列化操作将会失败,并且会抛出一个NotSerializableException,除非我们将不可序列化的引用标记为transient。
4、声明成transient的变量不被序列化工具存储,同样,static变量也不被存储。因为static代表类的状态,transient代表对象的临时数据。因此如果某个属性不需要被序列化,可以添加transient关键字,在序列化对象的时候就不会对这个属性进行序列化了。
Java有哪些对象序列化的方式?
Java序列化对象的方式主要有原生的以流的方法进行的序列化、Json序列化和FastJson序列化。
不管使用哪种序列化方法被序列化的对象都必须实现Serializable接口。
(1)Java原生序列化
Java原生序列化方法即通过Java原生流(ObjectInputStream和ObjectOutputStream之间的转化)的方式进行的序列化。在序列化之前JavaBean实体类必须实现Serializable接口,否则无法序列化。
Java原生序列化代码示例如下:
首先定义一个Student类,实现Serializable接口。
package com.serializable.demo;
import java.io.Serializable;
//Student类用于演示对象的序列化,Student类通过实现Serializable接口拥有了序列化的能力
public class Student implements Serializable{
private String id;
private String name;
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;
}
}
编写测试类:
package com.serializable.demo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeIODemo {
//测试入口
public static void main(String[] args) throws Exception{
Student student=new Student();
student.setId("1");
student.setName("Lily");
serializeByIO(student);
}
//序列化和反序列化
public static void serializeByIO(Object obj) throws Exception{
//序列化
Long t1 = System.currentTimeMillis();
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(obj);
System.out.println("java serialize: " +(System.currentTimeMillis()- t1) + "ms; 总大小:" + byteOut.toByteArray().length );
//反序列化
Long t2 = System.currentTimeMillis();
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream objIn = new ObjectInputStream(byteIn);
Student stu = (Student) objIn.readObject();
System.out.println("java deserialize: " + (System.currentTimeMillis() - t2) + "ms; Student: stu.getId()=" + stu.getId()+";stu.getName()="+stu.getName());
}
}
运行结果:
(2)Json序列化
Json序列化一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。现在对数据的传输大都是使用json作为服务器端返回的数据格式。比如调用一个服务器接口,通常的请求为xxx.json?a=xxx&b=xxx的形式。要序列化的对象还是Student类,Json序列化的测试代码如下:
package com.serializable.demo;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SerializeJsonDemo {
//测试入口
public static void main(String[] args) throws Exception{
Student student=new Student();
student.setId("1");
student.setName("Lily");
serializeByJson(student);
}
//序列化
public static void serializeByJson(Object obj) throws Exception{
ObjectMapper mapper = new ObjectMapper();
//序列化
Long t1 = System.currentTimeMillis();
String writeValueAsString = mapper.writeValueAsString(obj);
System.out.println("json serialize: " + (System.currentTimeMillis() - t1) + "ms; writeValueAsString="+writeValueAsString+";总大小:" + writeValueAsString.length());
//反序列化
Long t2 = System.currentTimeMillis();
Student stu = mapper.readValue(writeValueAsString, Student.class);
System.out.println("json deserialize: " + (System.currentTimeMillis() - t2) + "ms; Student: stu.getId()=" + stu.getId()+";stu.getName()="+stu.getName());
}
}
运行结果:
(3)FastJson序列化
fastjson 是阿里巴巴开发的一个性能很好的Java 语言实现的Json解析器和生成器。
特点:速度快,测试表明fastjson具有极快的性能,超越任其他的java json parser。功能强大,支持多种对象格式。无依赖,能够直接运行在Java SE 5.0以上版本。
使用时候需引入FastJson第三方jar包。要序列化的对象还是Student类,FastJson序列化代码测试如下:
package com.serializable.demo;
import com.alibaba.fastjson.JSON;
public class SerializeFastJsonDemo {
//测试入口
public static void main(String[] args) throws Exception{
Student student=new Student();
student.setId("1");
student.setName("Lily");
serializeByFastJson(student);
}
//序列化和反序列化
public static void serializeByFastJson(Object obj) throws Exception{
//序列化
Long t1 = System.currentTimeMillis();
String text = JSON.toJSONString(obj);
System.out.println("fastJson serialize: " +(System.currentTimeMillis() - t1) + "ms; text="+text+"; 总大小:" + text.length());
//反序列化
Long t2 = System.currentTimeMillis();
Student stu = JSON.parseObject(text, Student.class);
System.out.println("json deserialize: " + (System.currentTimeMillis() - t2) + "ms; Student: stu.getId()=" + stu.getId()+";stu.getName()="+stu.getName());
}
}
可以发现:对于小数量的序列化操作,序列化后对象的所占大小上:json序列化和fastJson序列化所占大小较少的,java原生序列化较多。对于序列化耗时,java原生序列化耗时最少,其次是json,最后是fastJson。 不过这是对小数量的操作,大数据量的操作这三者性能之间的差别可能会与此不同。