> 文章列表 > 序列化与反序列化

序列化与反序列化

序列化与反序列化

JSON
JSON是一种轻量级的数据交换格式,易于编写也易于机器解析和生成。

JSON格式能有效提高网络传输效率,在传输时能够将程序中的数据类型序列化为json字符串,在接收方反序列化恢复原来的数据格式。

序列化与反序列化

JSON是一种键值对的格式,如下:

{"name":"小许","sex" : "男","age" : 18,"address":["北京","天津","河北"]
}

JSON简便的格式有高速的传输是数据在传输时的主要格式,基本上编程语言都支持编程语言内置结构的数据向json字符串转化。

序列化

在不同语言中有不同的方式,下面将介绍Java与Go语言的序列化与反序列化。在Java中一切皆对象,所以序列化非常容易,直接继承java.io.Serializable。一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

public class Person implements java.io.Serializable{private int id;private String name;private String sex;private String address;/**省略setter和getter*/
}

继承该对象后就可以调用如下函数序列化Java对象

public final void writeObject(Object x) throws IOException

并通过如下函数反序列化

public final Object readObject() throws IOException, ClassNotFoundException

Go语言对JSON操作的包均在encoding/json包下,包下提供了Marshal方法来序列化Go内置对象。Marshal函数返回v的json编码。

func Marshal(v interface{}) ([]byte, error)

//创建结构体
type Person struct {name    stringaddress string
}//序列化
per := Person{name:    "钢铁侠",address: "漫威",
}
perjson, err := json.Marshal(&per)
if err != nil {panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

序列化与反序列化

上面代码中序列化了一个Person对象,但打印时却打印失败,这是由于结构体成员都是小写的,只能在本包内访问,序列化没有意义,也不支持私有类的序列化。

type Person struct {Name    stringAddress string
}

将结构体改为公共类时就可以序列化了。
序列化与反序列化

不同于Java一切皆对象的性质,Go中除了结构体还有map,数组,切片等。

//定义一个map类型
func initMap() map[string]string {var tmp map[string]string = map[string]string{}tmp["1"] = "aaa"tmp["2"] = "bbb"tmp["3"] = "ccc"return tmp
}//对map序列化
a := initMap()ajson, err := json.Marshal(&a)
if err != nil {panic("ajson序列化失败")
}
fmt.Printf("%v\\n", ajson)
fmt.Println(string(ajson))

序列化与反序列化

//输出序列化时的数据类型
fmt.Printf("%T\\n", ajson)
fmt.Printf("%T\\n", string(ajson))

序列化与反序列化
可以看出序列化后时一个字节数组,通过string()函数将其转化为字符串,即为json字符串。

Go序列化时的tag标签的使用

在序列化时成员变量的名称均是首字母大写,然而在实际使用时需要统一书写规范,需要特定的名称,这就需要使用序列化时的tag标签。

{"Name":"钢铁侠","Address":"漫威"}

Go语言结构体序列化tag使用规则是在结构体字段后添加json:"name"并用反引号包裹。

type Person struct {Name    string `json:"person_name"`Address string `json:"person_address"`Age     int
}

在Name和Address使用了tag那么其序列化后的名称会变为自定义的person_name,Age成员没有使用tag因此不会改变。

per := Person{Name:    "钢铁侠",Address: "漫威",Age:     18,
}
perjson, err := json.Marshal(&per)
if err != nil {panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

序列化与反序列化
struct的tag只会在序列化时起作用不会影响结构体的使用。

反序列化

反序列化就是将序列化后的json字符串或者字节数组在转化为编程语言的内置数据结构。这个反序列化可以发生正在同一语言内,也可以发生在在不同语言中,例如,Java类序列化后网络传输到前端由json反序列化,或者其他任何后端语言将内置数据序列化后传输到前端。

在同一语言中对序列化的数据反序列化,Java实现方式与Go实现方式。

/**
go语言实现
*///定义结构体
type Person struct {Name    string `json:"person_name"`Address string `json:"person_address"`Age     int    `json:"person_age"`
}//序列化
per := Person{Name:    "钢铁侠",Address: "漫威",Age:     18,
}
perjson, err := json.Marshal(&per)
if err != nil {panic(err)
}
fmt.Printf("per序列化的json数据为为:%v", perjson)
fmt.Printf("per序列化的json字符串为:%v", string(perjson))

序列化与反序列化
序列化后为一个字节数组,可以通过string()方法转化为字符串。

func json.Unmarshal(data []byte, v any) error
该方法时反序列化方法,第一个参数为需要反序列化的字节数组,第二个参数为反序列化后数据的赋值变量。

//反序列化赋值变量
var per1 Person
err1 := json.Unmarshal(perjson, &per1)
if err1 != nil {panic(err1)
}
fmt.Printf("反序列化的数据per1%s,%s,%d", per1.Name, per1.Address, per1.Age)

序列化与反序列化

str := `{"person_name":"钢铁侠","person_address":"漫威","person_age":18}`var per2 Person
err2 := json.Unmarshal([]byte(str), &per2)
if err2 != nil {panic(err2)
}
fmt.Println(per2)

对字符串也可以反序列化,需要将字符串转化为字节数组,通过[]byte()方法。

/**
Java实现
*///定义类实现序列化接口java.io.Serializable
public class Person implements java.io.Serializable
{public String name;public String address;public int id;/*gettersettertoString...*/
}//实例化类并序列化类
Person per = new Person();
per.name = "小许";
per.address = "中国";
per.id = 111111;FileOutputStream fs = new FileOutputStream("./tmp/per.txt");
ObjectOutputStream out = new ObjectOutputStream(fs);
out.writeObject(e);
out.close();
fs.close();
System.out.printf("data is saved in ./tmp/per.txt");//反序列化
Person e = null;
FileInputStream fileIn = new FileInputStream("./tmp/Person.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("反序列化的对象",e);
System.out.println("name: " + e.name);
System.out.println("address: " + e.address);
System.out.println("id: " + e.id);

这个序列化的字节数组直接存储在文件中,一般情况下都直接网络传输如http协议传输到浏览器端,由浏览器内置解析器即js反序列化。

在前后端交互的过程中主要的数据传输方式就是json字符串串,一般将后端语言的内置对象及数据结构都序列化为json字符串,再由Javascript的JSON,parse()方法将json字符串转化为js的内置对象。

JS中内置了json字符串与json数据的转化方法,因此只需要再后端语言中将内置数据序列化为json字符串即可,这个过程是统一的,因此诞生了很多序列化工具,仅需少量的代码即可序列化,如阿里巴巴的fastjson,apache的jackson等。