在Java中,我们可以通过多种方式来创建对象,并且只要对象没有被回收我们都可以复用该对象。但是,我们创建出来的这些Java对象都是存在于JVM的堆内存中的。只有JVM处于运行状态的时候,这些对象才可能存在。一旦JVM停止运行,这些对象的状态也就随之而丢失了。
但是在真实的应用场景中,我们需要将这些对象持久化下来,并且能够在需要的时候把对象重新读取出来。Java的对象序列化可以帮助我们实现该功能。
对象序列化机制 (Obiect Serialization) 是Java语言内建的一种对象持久化方式,通过对象序列化,可以把对象的状态保存为字节数组,并且可以在有需要的时候将这个字节数组通过反序列化的方式再转换成对象。对象序列化可以很容易的在JVM中的活动对象和字节数组 (流)之间进行转换。
所以序列化就是把Java对象序列化成字节数组的过程,反序列化就是把字节数组再转换成Java对象的过程。
在Java中,只要一个类实现了java.io.Serializable;接口,那么它就可以被序列化,这里先上一段代码:
package com.ifbranch.test;
import java.io.Serializable;
import java.util.Date;
/**
* @author 昕宝爸爸爱编程
*
*/
@SuppressWarnings("all")
public class User implements Serializable {
private String name;
private int age;
private Date brithday;
private transient String gender;
private static final long serialIVersionUID = -6849794470754667710L;
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 Date getBrithday() {
return brithday;
}
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "User [name=" + name + ", "
+ "age=" + age + ", brithday=" + brithday + ", "
+ "gender=" + gender + "]";
}
}
Code 2 是对 User 类进行序列化 和 反序列化的Demo:
package com.ifbranch.test;
import org.apache.commons .io.FileUtils;
import org.apache.commons .io.IOUtils;
import java.io.*;
import java.util.Date;
/**
* @author 昕宝爸爸爱编程
*
*/
public class SerializableDemo {
public static void main(String[] args) {
//Initializes The Obiect
User user = new User();
user .setName("xinbaodad") ;
user.setGender("male") ;
user.setAge(23);
user.setBirthday(new Date());
System.out.println(user);
//Write Obj to File
ObjectOutputstream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeQuietly(oos);
}
//Read Obj from File
File file = new File("tempFile");
ObjectInputstream ois = null;
try {
ois = new ObjectInputstream(new FileInputstream(file));
User newUser = (User) ois.readObiect();
System.out.printIn(newUser);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeOuietly(ois);
try {
IOUtils.closeOuietly(ois);
} catch (IOException e) {
e.printstackTrace() ;
}
}
}
}
//output
//User[name='xinbaodad', age=23, gender=male, birthday=Tue Feb 02 17:37:38 CST 2016]
//User[name='xinbaodad', age=23, gender=null, birthday=Tue Feb 02 17:37:38 CST 2016]
以下几个和序列化&反序列化有关的知识点大家可以重点关注一下:
1、在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。
2、通过ObiectOutputStream和ObiectlnputStream对对象进行序列化及反序列化
3、虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化ID 是否一致 (就是 private static final long serialVersionUID)
4、序列化并不保存静态变量
5、要想将父类对象也序列化,就需要让父类也实现Serializable 接口
6、transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阳止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是0,对象型的是 null。
7、服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取这样可以一定程度保证序列化对象的数据安全。
如果使用Java原生的序列化机制 (即通过 ObjectOutputStream 和 ObjectlnputStream 类),则对象必须实现Serializable 接口。如果对象没有实现这个接口,尝试原生序列化会地出 NotSerializableException。
对于像Jackson、Gson这样的JSON序列化库或用于XML的库(如JAXB),对象不需要实现 Serializable 接口文些库使用反射机制来访问对象的字段,并将它们转换成JSON或XML格式。在这种情况下,对象的序列化与Serializable 接口无关。