点击蓝字
关注我们
始于理论,源于实践,终于实战
老付话安全,每天一点点
激情永无限,进步看得见
严正声明
本号所写文章方法和工具只用于学习和交流,严禁使用文章所述内容中的方法未经许可的情况下对生产系统进行方法验证实施,发生一切问题由相关个人承担法律责任,其与本号无关。
特此声明!!!
什么是序列化
序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区,之后可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。这样一来,序列化使其他代码可以查看或修改那些不序列化便无法访问的对象实例数据。
反序列化是指将序列化后的字节流转换回对象或数据结构的过程。它通常用于从磁盘加载保存的对象或接收通过网络传输的序列化数据,通过反序列化,可以重新构建对象并恢复其之前序列化的状态和数据。
序列化的应用场景
-
数据存储:将对象序列化后保存到文件或数据库中,以便在程序重启后能够恢复对象的状态。
-
网络传输:在网络通信中,将对象序列化为字节流,通过网络传输到另一端,再反序列化为对象,实现跨进程甚至跨机器的对象传递。
-
对象复制:通过序列化和反序列化,可以实现对象的深拷贝,即创建一个与原对象完全相同的新对象。
-
分布式计算:在分布式计算环境中,任务和数据往往需要在不同的计算节点之间传递,序列化技术可以简化这一过程。
如何实现序列化
-
Java:在Java中,可以通过实现Serializable接口来标记一个类是可序列化的。然后使用ObjectOutputStream类的writeObject方法将对象序列化,使用ObjectInputStream类的readObject方法将对象反序列化。
-
C#:在C#中,可以通过实现ISerializable接口来实现自定义的序列化和反序列化逻辑。此外,.NET框架还提供了多种内置的序列化机制,如XML序列化和JSON序列化。
-
Python:在Python中,可以使用pickle模块来实现对象的序列化和反序列化。pickle模块提供了dump和load方法,分别用于将对象序列化到文件和从文件反序列化对象。
python序列化示例
以python为例进行解释序列化与反序列化。
模块 pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化。
代码示例:
import pickle
# 定义一个对类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 创建一个 Person 对象
person = Person("d4m1ts", 18)
# 序列化对象
serialized_data = pickle.dumps(person)
# 序列化后的二进制数据
print(f"序列化后的数据: {serialized_data}", end="nn")
# 反序列化数据
deserialized_person = pickle.loads(serialized_data)
# 访问反序列化后的对象属性
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")
print(f"name: {deserialized_person.name}") # 输出: d4m1ts
print(f"age: {deserialized_person.age}") # 输出: 18
魔术方法
魔术方法(Magic Methods),也称为特殊方法(Special Methods)或双下划线方法(Dunder Methods),是面向对象编程中的一种特殊方法。它们通常以双下划线(__)开头和结尾,例如__init__、__str__、__add__等。这些方法在特定的情况下被编程语言的解释器或编译器自动调用,而不是直接在代码中显式地调用。
魔术方法的主要作用是提供一种机制来实现面向对象编程的一些高级特性,例如:
-
定制类的行为:通过重写魔术方法,你可以改变一个类的对象如何与编程语言内置的操作符和函数交互。例如,通过重写__add__方法,你可以定义两个对象相加时的行为。
-
控制类的生命周期:一些魔术方法用于控制对象的创建、复制、删除等生命周期事件。例如,__init__方法用于初始化对象,__del__方法用于销毁对象。
-
提供便捷的方法访问:一些魔术方法用于提供便捷的属性访问和修改方式。例如,__getitem__方法用于实现对象的索引访问,__setitem__方法用于实现对象的索引赋值。
魔术方法reduce()
在Python中,__reduce__()是一个特殊方法,用于定义对象的序列化行为。当使用pickle模块对对象进行序列化和反序列化时,__reduce__()方法会被调用。
__reduce__()方法应该返回一个元组(),其中包含两个或三个元素。元组的第一个元素是用于重新构建对象的函数,第二个元素是传递给构建函数的参数(通常是一个元组),而第三个元素(可选)是用于恢复对象状态的可迭代对象。
简单来说,我们可以通过重写__reduse__()函数,来修改数据反序列化的方式。
import pickle
# 定义一个类
class Person:
def __init__(self, name, age):#初始化类的属性
self.name = name
self.age = age
def __reduce__(self):#返回一个元组
print("Calling __reduce__()")#打印一条消息Calling __reduce__()
return (print, ("reduse poc test",))
# 创建一个 Person 对象
person = Person("d4m1ts", 18)
# 序列化对象
serialized_data = pickle.dumps(person)
# 序列化后的二进制数据
print(f"序列化后的数据: {serialized_data}", end="nn")
# 反序列化数据
deserialized_person = pickle.loads(serialized_data)
# 访问反序列化后的对象属性
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")
print(f"name: {deserialized_person.name}") # 输出: d4m1ts
print(f"age: {deserialized_person.age}") # 输出: 18
javascript序列化与反序列化
#定义了一个名为 Student 的公共类,该类实现了 Serializable 接口,这意味着该类的对象可以被序列化,即可以被转换为字节流以便存储或传输。
public class Student implements Serializable{
#静态的、最终的、长整型的变量,标识类的版本。在序列化和反序列化过程中,Java 使用这个 ID 来确保类的版本一致性。
private static final long serialVersionUID = -6060343040263809614L;
#定义私有成员变量,字符串变量 userName、password,year
private String userName;
private String password;
private String year;
#定义一个公共方法 getUserName,用于获取 userName 的值。返回一个字符串类型的值。
public String getUserName() {
return userName;
}
#定义一个公共方法 getpassword,
public String getPassword() {
return password;
}
#公共方法,返回类型为void,表示该方法不返回任何值。方法名是setUserName,参数是一个String类型的变量userName。
public void setUserName(String userName) {
#将传入的userName参数赋值给类的成员变量this.userName 。this关键字用于引用当前对象的成员变量。
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
#构造方法,用于初始化 Student 对象
public Student(String userName, String password, String year) {
this.userName = userName;
this.password = password;
this.year = year;
}
}
PHP序列化与反序列化
header("content-type:text/html;charset=utf-8");
class person {
public $name;
public $age;
public $sex;
public $lover;
#构建函数初始化person对象的属性
public function __construct($name,$age,$sex,$lover)
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
$this->lover = $lover;
}
#在对象序列化之前调用,返回一个数组,指定哪些属性需要被序列化。
public function __sleep()
{
// 在这里决定哪些被序列化,echo类似print,<br>换行符
echo "<br>序列化调用";
return array("name","age","lover");
}
public function __wakeup()
{
echo "<br> 反序列化调用";
}
}
#创建对象
$person = new person("小雪","12","女","猪");
#序列化对象
$person_str = serialize($person);
echo $person_str;
// 反序列化
$person_obj = unserialize($person_str);
#输出反序列化后的对象
var_dump($person_obj);
END
老付
欢迎扫码
关注我们
网络安全
原文始发于微信公众号(老付话安全):什么是序列化与反序列化
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论