先不讲题目,先讲讲序列化和反序列化。
一,序列化与反序列化
在Java中,序列化和反序列化是用于将对象转换为字节流和将字节流转换回对象的过程。序列化是将对象转换为字节流,以便可以在网络上传输或保存到文件中。而反序列化则是将字节流重新转换回对象。
Java提供了一个java.io.Serializable
接口,通过实现该接口,可以使类变得可序列化。该接口是一个标记接口,不包含任何方法,仅用于标识类的实例可以进行序列化。当一个类实现了Serializable
接口后,它的所有非瞬态(non-transient)的实例变量都可以被序列化。
下面是一个简单的示例,展示了如何在Java中进行序列化和反序列化:
import java.io.*;
public class SerializationDemo {
public static void main(String[] args) {
// 序列化对象
try {
// 创建对象
MyClass obj = new MyClass("Hello, World!");
// 创建文件输出流
FileOutputStream fileOut = new FileOutputStream("object.ser");
// 创建对象输出流
ObjectOutputStream out = new ObjectOutputStream(fileOut);
// 序列化对象
out.writeObject(obj);
// 关闭输出流
out.close();
// 关闭文件输出流
fileOut.close();
System.out.println("对象已序列化到 object.ser 文件");
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化对象
try {
// 创建文件输入流
FileInputStream fileIn = new FileInputStream("object.ser");
// 创建对象输入流
ObjectInputStream in = new ObjectInputStream(fileIn);
// 反序列化对象
MyClass obj = (MyClass) in.readObject();
// 关闭输入流
in.close();
// 关闭文件输入流
fileIn.close();
System.out.println("从 object.ser 文件反序列化得到对象:");
System.out.println(obj.getMessage());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class MyClass implements Serializable {
private String message;
public MyClass(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
在上面的示例中,我们创建了一个MyClass
类,它实现了Serializable
接口。然后,我们创建一个MyClass
对象并将其序列化到文件object.ser
中。接下来,我们从文件中反序列化对象,并打印出getMessage()
方法返回的消息。
需要注意的是,如果一个类的某些字段不希望被序列化,可以将其标记为transient
关键字。在上述示例中,如果message
字段被声明为transient
,那么它将不会被序列化。
另外,需要注意的是,序列化和反序列化的过程依赖于类的结构和版本。如果在序列化对象后,修改了类的结构或版本,那么在反序列化时可能会出现异常。为了避免这种情况,建议在类中声明一个名为serialVersionUID
的静态常量,用于标识类的版本号。当类的结构或版本发生变化时,应更新serialVersionUID
的值。这样可以确保反序列化时的兼容性。
这就是Java中序列化和反序列化的基本概念和用法。通过序列化和反序列化,可以方便地在Java应用程序之间或与外部系统之间传输对象数据。
---------------------------------------------------------------------------------------------------------------------------------
以上都是chatgpt生成的,总结一下就是,序列化把对象转换成字节流,为了方便在网络中传输和保存在硬盘,反序列化就反过来。通过实现ava.io.Serializable
接口,可以使类变得可序列化。如果一个类的某些字段不希望被序列化,可以将其标记为transient
关键字。
二,题解
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
return rserialize(root, "");
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] dataArray = data.split(",");
List<String> dataList = new LinkedList<String>(Arrays.asList(dataArray));
return rdeseralize(dataList);
}
public String rserialize(TreeNode root, String str){
if(root == null){
str += "None,";
}else{
str += str.valueOf(root.val) + ",";
str = rserialize(root.left, str);
str = rserialize(root.right, str);
}
return str;
}
public TreeNode rdeseralize(List<String> dataList){
if(dataList.get(0).equals("None")){
dataList.remove(0);
return null;
}
TreeNode root = new TreeNode(Integer.valueOf(dataList.get(0)));
dataList.remove(0);
root.left = rdeseralize(dataList);
root.right = rdeseralize(dataList);
return root;
}
}
正真序列化与反序列化的方法是rserialize()和rdeserialize(),serialize()和deserialize()调用了这两个正真的序列化与反序列化方法。
rserialize()就是以根左右的方式遍历这个树,如果遍历到的节点是null,就在str后面加一个Node,否则就加”值,“,然后把它的左孩子加进去,然后把左孩子的左孩子加进去...然后加最小的右孩子...这样就完成了序列化,serialize()调用rserialize()就行。
deserialize()先用split方法把str以”,“分开,放入一个String数组里面,再通过Arrays.asList()方法转换成List,然后作为参数通过构造方法new一个LinkedList,然后调用rdeseralize()方法,这个方法传的参数就是一个包含每个节点值的list,这个值是Strign类型。
rdeseralize()是每次取出List的第一个元素,如果是”None“,就直接删掉返回一个null,否则就拿到这个元素通过Integer.valueOf()方法转换成Integer类型,创建一个新节点,节点的val就是这个值。然后删掉list的第一个元素,然后节点的左孩子调用这个方法,于是第二个元素就给了节点的左孩子,这样就实现了与序列化相反的反序列化。