面试题答案
一键面试实现思路
- 定义结构体:定义嵌套结构体,对于需要自定义序列化和反序列化的字段,使用
json
标签指定其在 JSON 中的键名。 - 实现自定义序列化接口:为需要特殊处理的类型(如时间类型)实现
json.Marshaler
和json.Unmarshaler
接口,在接口方法中实现自定义的序列化和反序列化逻辑。 - 使用标准库进行序列化和反序列化:使用
encoding/json
包的Marshal
和Unmarshal
函数对结构体进行 JSON 序列化和反序列化操作。
关键代码示例
以 Go 语言为例:
package main
import (
"encoding/json"
"fmt"
"time"
)
// 自定义时间类型
type MyTime struct {
time.Time
}
// 实现 json.Marshaler 接口
func (t MyTime) MarshalJSON() ([]byte, error) {
// 以 "YYYY-MM-DD HH:MM:SS" 格式序列化
return []byte(`"` + t.Time.Format("2006-01-02 15:04:05") + `"`), nil
}
// 实现 json.Unmarshaler 接口
func (t *MyTime) UnmarshalJSON(data []byte) error {
var err error
// 去掉双引号
s := string(data[1 : len(data)-1])
t.Time, err = time.Parse("2006-01-02 15:04:05", s)
return err
}
// 嵌套结构体
type NestedStruct struct {
ID int
Name string
Time MyTime
}
func main() {
// 初始化结构体
ns := NestedStruct{
ID: 1,
Name: "example",
Time: MyTime{time.Now()},
}
// 序列化
serialized, err := json.Marshal(ns)
if err != nil {
fmt.Println("序列化错误:", err)
return
}
fmt.Println("序列化结果:", string(serialized))
// 反序列化
var deserialized NestedStruct
err = json.Unmarshal(serialized, &deserialized)
if err != nil {
fmt.Println("反序列化错误:", err)
return
}
fmt.Println("反序列化结果:", deserialized)
}
可能遇到的问题及解决方案
- JSON 格式错误:
- 问题:在自定义序列化和反序列化过程中,生成的 JSON 格式可能不符合标准,导致反序列化失败。
- 解决方案:仔细检查自定义序列化和反序列化逻辑,确保生成的 JSON 字符串格式正确,特别是在处理特殊字符和引号时。
- 时间格式解析失败:
- 问题:如果自定义的时间格式与实际解析的格式不一致,会导致反序列化时时间解析失败。
- 解决方案:确保
MarshalJSON
和UnmarshalJSON
方法中使用的时间格式一致,并且与实际数据的格式匹配。
- 循环引用:
- 问题:嵌套结构体中可能存在循环引用,导致序列化时陷入无限循环。
- 解决方案:在设计结构体时避免循环引用,或者使用第三方库(如
json-iterator/go
),它对循环引用有更好的支持。
- 性能问题:
- 问题:过多的自定义序列化和反序列化逻辑可能会影响性能,特别是在处理大量数据时。
- 解决方案:尽量简化自定义逻辑,避免不必要的计算和转换,对于性能敏感的场景,可以考虑使用其他更高效的序列化方式(如 protobuf)。