序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象同理,反序列化就是把字节序列恢复为Java对象的过程。通俗易懂的来说就好比好莱坞大片里面的瞬移,将一个人或者物体变成一串数字和字母流,然后传送到很远的地方再将这一串数字和字母流变回原来的物体。这一过程和java的序列化反序列化很像,将物体变成数字字母流就是序列化,将数字字母流变成物体就是反序列化。通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。
对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码获得该权限。
简单来说就好比我们看大科幻电影 里面有很多的情节是这样的 将一个人或者物体变成一串数字和字母流 然后传送到很远的地方再将这一串数字和字母流变回原来的物体 这一过程和序列化反序列化很像 将物体变成数字字母流就是序列化 将数字字母流变成物体就是反序列化
在实现Java对象的序列化与反序列化的过程中我们需要注意以下几点:
1.如果对象要进行序列化需要实现Serializable接口
2.ObjectOutputStream 用于序列化
3.ObjectInputStream 用于反序列化
4.transient修饰的变量不可以序列化
5.static 修饰的变量不能被序列化
实现java对象的序列化与反序列化的代码实现如下:
import java.io.*;
//实现serializable接口才可以实现对象的序列化
class Person implements Serializable {
public String name;
public int age;
public String sex;
//transient修饰的变量不可以序列化
transient public String cardId;
//static 修饰的变量不能被序列化
public static String phoneNum;
public Person(String name, int age, String sex, String cardId) {
= name;
this.age = age;
this.sex = sex;
this.cardId = cardId;
}
public static void setPhoneNum(String phoneNum) {
Person.phoneNum = phoneNum;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", cardId='" + cardId + '\'' +
", phoneNum='" + phoneNum + '\'' +
'}';
}
}
public class SerializTest {
public static void main(String[] args) {
Person.person = new Person("Listen", 21, "MAN", "100100100111");
Person.setPhoneNum("120");
//序列化一个对象
serializPreson(person);
//反序列化一个对象
Person personRet = desSerializable();
System.out.println(personRet);
}
private static Person desSerializable() {
Person person = null;
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\java\\java.txt"))){
person = (Person) objectInputStream.readObject();
System.out.println("反序列化成功");
} catch (IOException | ClassNotFoundException e) {
e.getStackTrace();
}
return person;
}
private static void serializPreson(Person person) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\java\\java.txt"))){
//将person对象序列化输入文件
// 这个 writeObject 集序列化+写文件 两者同时搞定
objectOutputStream.writeObject(person);
System.out.println("序列化成功");
} catch (IOException e) {
e.getStackTrace();
}
}
}
从上面的结果我们可以看到cardId被transient修饰不能被序列化,所以得到的反序列化结果他的值就是null 。但是我们说被static修饰的phoneNum也不能序列化,但是此处它尽然不显示null,这是因为他是静态变量,在代码编译期间就已经存储在方法区的,所以他不需要序列化也可以获得值。
一个类如果想被序列化,需要实现一个Serialzable接口。类中的静态变量的值是不会进行序列化的,transient修饰的属性,是不会被序列化的,内置类型为对应的0值。引用类型为null。在实现这个Serializable接口的时候,一定要给这个serialVersionUID赋值,最好设置为1L,不同的serialVersionUID的值,会影响到反序列化。掌握了java序列化与反序列化,能够让我们对系统的性能有更好的提升,使程序更具维护性。