Serialization is the conversion of the state of an object into a byte stream; deserialization does the opposite.
[2]
序列化: 将对象转换成字节流,以便将对象信息持久存储起来。三体人的脱水
反序列化: 将字节流转换为对象,以便将持久存储的对象信息加载为真正的对象。三体人的浸泡
那么脱水之后就方便携带、存储、传输,甚至是 —— 永生(这就是序列化的目的,将对象信息持久存储起来,毕竟大刘也没说脱水后的三体人会不会死),等到恒纪元来临时,就可以浸泡,将来的某一天,也会诞生对人的序列化与反序列化技术,即将思想和记忆上传至云端,然后等新的肉体成长好再下载到新的肉体里,这种技术对伦理的颠覆将是前所未有的。实际上这样去思考对象的序列化,你会发现一些共通之处。
序列化的一些规定
- (1)属于这个类的static属性。就像人的眼睛数量就是人这个类的static属性,没变异的话,
nums_of_eye=2
是恒定的,没必要对固定不变的重复事情序列化。- (2)如果有成员变量为类,那么这个类也必须可以被序列化。
- (3)
transient
关键字。用在序列化中,所以平常几乎没什么机会见到它,如果你不想某些属性被序列化,那就在这个属性前面加上transient
[7],就比如,女人永远都是刚满十八岁,dddd
,所以嘛,女生对于年龄这种敏感信息从来都不会写在纸上,你得用心体会。据说华为OD某员工说因为代码编程时,输出了用户个人信息,被领导一顿批,搞不好就是这种细节的地方没注意到,谁知道呢,知道的可以留个言。
// Person.java
import java.io.Serializable;
/**
* @ClassName: Person
* @Author: 键盘国治理专家
* @email: ?????????@qq.com
* @Time: 2024/1/10 下午2:46
* @Description:该类涉及以下知识点
* (1)类成员属性的默认作用域为default
* (2)private static final long serialVersionUID = 1L;的作用?
序列化前和反序列化后,这个UID都必须相同,
要不然序列化的不是同一个对象,就会报错,如果不写的话,JVM会自动生成,但是这样就不保证可移植性了,因为这取决于编译器,所以高度建议手写
* (3)transient关键字的作用?
如果你不想某些属性被序列化,那就在这个属性前面加上transient
*
* @Version: 1.0
*/
public class Person implements Serializable {
/*
static的变量不会被序列化,那么这个ID会吗?
前面说过了,static是不会的,那么这个ID显然也是不能例外的,
那么JVM如何检查序列化前和序列化后的这个ID值是否一致呢?
通过Hash函数,想了解更多,请看参考文章[1]。
*/
private static final long serialVersionUID = 2L;
static String country = "ITALY"; //不会被序列化,作用域为默认的default
private int age;
private String name;
transient int height; //transient??
// getters and setters
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
//TestDemo.java
import java.io.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @ClassName: Main
* @Author: 键盘国治理专家
* @email: ?????????@qq.com
* @Time: 2024/1/10 下午2:50
* @Description:
* @Version: 1.0
*/
public class TestDemo {
@Test
public void whenSerializingAndDeserializing_ThenObjectIsTheSame() throws IOException, ClassNotFoundException {
Person person = new Person();
person.setAge(20);
person.setName("Joe");
person.setHeight(199);
// (1)Writing an object into a file.
FileOutputStream fileOutputStream
= new FileOutputStream("./yourfile.txt");
ObjectOutputStream objectOutputStream
= new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(person);
objectOutputStream.flush();
objectOutputStream.close();
// (2)Reading an object from a file.
FileInputStream fileInputStream
= new FileInputStream("./yourfile.txt");
ObjectInputStream objectInputStream
= new ObjectInputStream(fileInputStream);
Person p2 = (Person) objectInputStream.readObject();
objectInputStream.close();
assertTrue(p2.getAge() == person.getAge());
assertTrue(p2.getName().equals(person.getName()));
// height加了transient,不会被序列化
System.out.println(p2.getHeight()); // 0
System.out.println(p2.getHeight() == person.getHeight()); //False
}
}
下面说下共通之处,共有三点,血肉苦弱,机械飞升,借助外在的设备,将人的信息持久的保存起来,等到以后有了合适的科学条件,再把个人的信息下载到新的皮囊里,那么很显然,你能上传的只有思维,你怎么知道上传的思维经过数百年数千年的变化后,与你上传前的东西一致,而不是与之相似的另一个双胞胎的思维呢?这就是serialVersionUID
的作用,这是第一点;你的一切骨架和其它硬件都被抛弃了,这就是static
变量不会被初始化的道理,因为下一幅皮囊还有,这是第二点;你不想留给下辈子的记忆也可以选择性抛弃,这就是Java
中的transient
关键字所做的,不想要被序列化的东西不要,这是第三点。