一、啥是序列化
在计算机的世界里,序列化就像是给数据穿上一件能在不同地方“旅行”的外套。简单来说,序列化就是把对象变成一种可以存储或者传输的格式,反序列化呢,就是把这个格式再变回对象。在 Dart 里,最常见的序列化格式就是 JSON 了。为啥选 JSON 呢?因为它简单、通用,好多编程语言都支持。
比如说,你有一个 Dart 对象,里面有一些属性,像名字、年龄啥的。如果你想把这个对象存到文件里,或者通过网络发给别人,就需要把它变成 JSON 格式。等对方收到后,再把 JSON 变回对象。这一过程就是序列化和反序列化。
二、Dart 里的 JSON 转换
简单对象的 JSON 转换
在 Dart 里,要做 JSON 转换,得用到 dart:convert 这个库。咱先看个简单的例子:
// Dart 技术栈
import 'dart:convert';
// 定义一个简单的类
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
// 将对象转换为 Map
Map<String, dynamic> toJson() {
return {
'name': name,
'age': age,
};
}
// 从 Map 创建对象
factory Person.fromJson(Map<String, dynamic> json) {
return Person(
json['name'],
json['age'],
);
}
}
void main() {
// 创建一个 Person 对象
Person person = Person('张三', 25);
// 将 Person 对象转换为 JSON 字符串
String jsonString = json.encode(person.toJson());
print('JSON 字符串: $jsonString');
// 将 JSON 字符串转换回 Person 对象
Map<String, dynamic> jsonMap = json.decode(jsonString);
Person newPerson = Person.fromJson(jsonMap);
print('新的 Person 对象: ${newPerson.name}, ${newPerson.age}');
}
在这个例子里,我们定义了一个 Person 类,有 name 和 age 两个属性。toJson 方法把对象变成一个 Map,fromJson 方法从 Map 创建对象。然后用 json.encode 把 Map 变成 JSON 字符串,用 json.decode 把 JSON 字符串变回 Map,最后再用 fromJson 方法把 Map 变成 Person 对象。
嵌套对象的 JSON 转换
有时候,对象里还会包含其他对象,这就是嵌套对象。看下面的例子:
// Dart 技术栈
import 'dart:convert';
// 定义一个 Address 类
class Address {
String city;
String street;
// 构造函数
Address(this.city, this.street);
// 将对象转换为 Map
Map<String, dynamic> toJson() {
return {
'city': city,
'street': street,
};
}
// 从 Map 创建对象
factory Address.fromJson(Map<String, dynamic> json) {
return Address(
json['city'],
json['street'],
);
}
}
// 定义一个 Person 类,包含 Address 对象
class Person {
String name;
int age;
Address address;
// 构造函数
Person(this.name, this.age, this.address);
// 将对象转换为 Map
Map<String, dynamic> toJson() {
return {
'name': name,
'age': age,
'address': address.toJson(),
};
}
// 从 Map 创建对象
factory Person.fromJson(Map<String, dynamic> json) {
return Person(
json['name'],
json['age'],
Address.fromJson(json['address']),
);
}
}
void main() {
// 创建一个 Address 对象
Address address = Address('北京', '长安街');
// 创建一个 Person 对象
Person person = Person('李四', 30, address);
// 将 Person 对象转换为 JSON 字符串
String jsonString = json.encode(person.toJson());
print('JSON 字符串: $jsonString');
// 将 JSON 字符串转换回 Person 对象
Map<String, dynamic> jsonMap = json.decode(jsonString);
Person newPerson = Person.fromJson(jsonMap);
print('新的 Person 对象: ${newPerson.name}, ${newPerson.age}, ${newPerson.address.city}, ${newPerson.address.street}');
}
在这个例子里,Person 类里有一个 Address 对象。toJson 方法把 Address 对象也变成 Map 放到 Person 的 Map 里,fromJson 方法从 Map 里取出 Address 的 Map,再用 Address.fromJson 方法创建 Address 对象。
三、自定义编码解码器
有时候,JSON 转换的默认规则不能满足我们的需求,这时候就需要自定义编码解码器了。
自定义编码器
自定义编码器就是自己定义把对象变成 JSON 字符串的规则。看下面的例子:
// Dart 技术栈
import 'dart:convert';
// 定义一个简单的类
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
}
// 自定义编码器
class PersonEncoder extends JsonEncoder {
@override
String convert(Object? object) {
if (object is Person) {
return '{"name": "${object.name}", "age": ${object.age}}';
}
return super.convert(object);
}
}
void main() {
// 创建一个 Person 对象
Person person = Person('王五', 35);
// 使用自定义编码器将 Person 对象转换为 JSON 字符串
PersonEncoder encoder = PersonEncoder();
String jsonString = encoder.convert(person);
print('自定义编码后的 JSON 字符串: $jsonString');
}
在这个例子里,我们定义了一个 PersonEncoder 类,继承自 JsonEncoder。重写了 convert 方法,当对象是 Person 类型时,按照我们自己的规则把它变成 JSON 字符串。
自定义解码器
自定义解码器就是自己定义把 JSON 字符串变回对象的规则。看下面的例子:
// Dart 技术栈
import 'dart:convert';
// 定义一个简单的类
class Person {
String name;
int age;
// 构造函数
Person(this.name, this.age);
}
// 自定义解码器
class PersonDecoder extends JsonDecoder {
@override
Object? convert(String input) {
Map<String, dynamic> jsonMap = json.decode(input);
return Person(jsonMap['name'], jsonMap['age']);
}
}
void main() {
// 定义一个 JSON 字符串
String jsonString = '{"name": "赵六", "age": 40}';
// 使用自定义解码器将 JSON 字符串转换为 Person 对象
PersonDecoder decoder = PersonDecoder();
Person person = decoder.convert(jsonString) as Person;
print('自定义解码后的 Person 对象: ${person.name}, ${person.age}');
}
在这个例子里,我们定义了一个 PersonDecoder 类,继承自 JsonDecoder。重写了 convert 方法,把 JSON 字符串变成 Map,再用 Map 创建 Person 对象。
四、应用场景
数据存储
当你想把对象存到文件或者数据库里时,就需要把对象序列化。比如,你有一个用户信息的对象,要把它存到本地文件里,就可以把它变成 JSON 字符串再存。等需要用的时候,再把 JSON 字符串反序列化回对象。
网络传输
在网络通信中,数据需要在不同的设备之间传输。这时候就需要把对象序列化,变成可以在网络上传输的格式,比如 JSON。接收方收到后,再把 JSON 反序列化回对象。
缓存
有时候,为了提高性能,会把一些经常使用的数据缓存起来。这时候就可以把对象序列化后存到缓存里,等需要用的时候再反序列化。
五、技术优缺点
优点
- 简单通用:JSON 格式简单易懂,好多编程语言都支持,方便不同系统之间的数据交换。
- 可读性强:JSON 字符串是文本格式,人也能很容易看懂,方便调试和维护。
- 灵活性高:可以自定义编码解码器,满足不同的需求。
缺点
- 性能问题:序列化和反序列化过程会消耗一定的性能,尤其是处理大量数据的时候。
- 安全问题:如果 JSON 数据来自不可信的来源,可能会存在安全风险,比如 JSON 注入攻击。
六、注意事项
处理异常
在进行 JSON 转换时,可能会出现各种异常,比如 JSON 格式错误。所以要做好异常处理,避免程序崩溃。
// Dart 技术栈
import 'dart:convert';
void main() {
String jsonString = '{"name": "孙七", "age": 45'; // 错误的 JSON 格式
try {
Map<String, dynamic> jsonMap = json.decode(jsonString);
print('JSON 解码成功');
} catch (e) {
print('JSON 解码失败: $e');
}
}
数据类型问题
JSON 里只有几种基本的数据类型,比如字符串、数字、布尔值等。在进行序列化和反序列化时,要注意数据类型的转换。
自定义编码解码器的复杂度
自定义编码解码器虽然灵活,但也会增加代码的复杂度。要根据实际需求来决定是否使用。
七、文章总结
Dart 里的序列化和 JSON 转换是很重要的技术,能让我们在不同场景下方便地存储、传输和处理数据。通过 dart:convert 库,我们可以轻松地进行简单对象和嵌套对象的 JSON 转换。当默认的转换规则不能满足需求时,还可以自定义编码解码器。不过,在使用过程中,要注意处理异常、数据类型问题,以及自定义编码解码器的复杂度。
评论