.为什么要序列化
对象不序列化,能直接存储吗?
在 Java 中,序列化是将对象的状态信息转换为可以存储或传输的形式(例如,转换为字节流)的过程。在对象数据需要在网络上传输或需要在磁盘上持久化存储时,序列化是必不可少的
对象在没有序列化的情况下不能直接存储在像文件系统或数据库这样的持久化存储中。序列化是将对象的状态转换为一种可以存储或传输的格式的过程。
没有序列化,对象是一个内存中的数据结构,不能直接存储到硬盘或通过网络传输。如果要持久化存储或在网络间传输一个对象,您需要先将其序列化为如二进制、JSON、XML 等格式。
这些格式可以被写入文件系统、数据库或通过网络发送,并在需要时反序列化回原始对象。
java中的序列化几种形式
Java 原生序列化:通过实现 java.io.Serializable 接口。对象被转换成二进制流以便于存储或传输。
JSON 序列化:使用库如 Jackson 或 Gson,将对象转换为 JSON 格式的字符串。
XML 序列化:使用如 JAXB (Java Architecture for XML Binding) 等库将对象转换为 XML 格式。
Google Protocol Buffers:一种语言和平台无关的高效二进制序列化库。
Apache Avro:支持丰富的数据结构的数据序列化系统。
Kryo:一个快速高效的 Java 二进制序列化和反序列化库。
以下以Serializable 和 JSON做分析
java 原生的序列化机制Serializable
在 Java 中,可以通过 原生的序列化机制。实现 java.io.Serializable 接口来启用对象的序列化。这个接口是一个标记接口,它不包含任何方法,仅标记类的对象可以被序列化。
版本兼容性:如果序列化的对象在不同版本之间发生变化,可能会遇到兼容性问题。为此,可以使用 serialVersionUID 来管理版本。
transient 关键字:如果您的类中有一些不需要序列化的字段(无论是 String 类型还是其他类型),可以使用 transient 关键字标记这些字段。
private int myInt; // 基本类型 int
在 Java 中,基本数据类型(如 int、double、boolean 等)本身并不实现 Serializable 接口,因为它们不是对象。但是,当基本数据类型被用作类的字段时,在该类实现了 Serializable 接口的情况下,这些基本数据类型的字段会自动包含在序列化过程中。
这意味着,如果您创建了一个实现了 Serializable 接口的类,并且这个类包含基本数据类型的字段,那么当您序列化这个类的对象时,这些基本数据类型的字段也会被序列
通常Serializable 序列化会有乱码
序列化过程生成的二进制数据不仅包含字符串的内容,还包含了 Java 对象序列化的附加信息,如类信息、序列化版本 ID 等。
这部分数据在文本编辑器中通常显示为乱码,因为它们包含非文本字符
Serializable序列化的的二进制,查看可以用二进制编辑器查看,不过可是不可识别的字符
(Notepad++ 安装插件 HEX-Editor 8.5.3Notepad++ 下载0.9.12 HEX-Editor)
测试 HashMap序列化与反序列化
package com.example.demo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.HashMap;
public class SerializeExample {
public static void main(String[] args) {
String str = “Hello, World!”; // 字符串对象
try {
// 创建一个指向文件的输出流
FileOutputStream fileOut = new FileOutputStream(“D:\file.bin”);
// 创建一个对象输出流,并将其包装在 fileOut 流中
ObjectOutputStream out = new ObjectOutputStream(fileOut);
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(“key”,“111”);
// 序列化字符串对象
out.writeObject(hashMap);
// 关闭所有流
out.close();
fileOut.close();
System.out.println("Serialized data is saved in string.ser");
} catch (IOException i) {
i.printStackTrace();
}
}
}
package com.example.demo;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;
public class DeserializeExample {
public static void main(String[] args) {
HashMap<String,String> str = new HashMap();
try {
// 创建一个指向文件的输入流
FileInputStream fileIn = new FileInputStream(“D:\file.bin”);
// 创建一个对象输入流,并将其包装在 fileIn 流中
ObjectInputStream in = new ObjectInputStream(fileIn);
// 反序列化字符串对象 反序列化时使用 ObjectInputStream 读取序列化的对象数据,会返回一个 Object 类型的实例。如果您知道该对象的具体类型,通常需要进行显式的类型转换(强转)以恢复到其原始类型。
str = (HashMap<String, String>) in.readObject();
str.forEach((k,v)->{
System.out.println(k+" "+v);
});
// 关闭所有流
in.close();
fileIn.close();
System.out.println("Deserialized String: " + str);
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("String class not found");
c.printStackTrace();
return;
}
}
}
二:JSON序列化
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式(一种格式)。JSON 使用文本格式来表示对象,使其网络上进行数据传输,被绝大多数编程语言解析。
普通文本对象打印为:对象信息,别人无法识别
package com.example.demo;
import com.alibaba.fastjson.JSON;
import java.io.FileWriter;
import java.io.IOException;
public class JsonToFileExample {
public static void main(String[] args) {
// 创建要序列化的对象
MyObject obj = new MyObject();
obj.setName("Example Name");
obj.setValue(123);
// 使用 Fastjson 将对象转换为 JSON 字符串
// String jsonString = JSON.toJSONString(obj);
// 将 JSON 字符串保存到文件
try (FileWriter file = new FileWriter("D:\\object.txt")) {
file.write(obj.toString());
file.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
static class MyObject {
private String name;
private int value;
// getters 和 setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
如果转成json则可以打印为:
public class JsonToFileExample {
public static void main(String[] args) {
// 创建要序列化的对象
MyObject obj = new MyObject();
obj.setName("Example Name");
obj.setValue(123);
// 使用 Fastjson 将对象转换为 JSON 字符串
String jsonString = JSON.toJSONString(obj);
// 将 JSON 字符串保存到文件
try (FileWriter file = new FileWriter("D:\\object.txt")) {
file.write(jsonString);
file.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
static class MyObject {
private String name;
private int value;
// getters 和 setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
在 Spring Boot 项目中,使用 Feign 进行远程调用时,对象的传输通常不依赖于 Java 的原生序列化机制(即实现 Serializable 接口)。
Feign 和其他 Spring Cloud 组件在进行远程调用时,会使用 HTTP 协议,并且通常结合了如 JSON 或 XML 等格式的 HTTP 消息转换器来序列化和反序列化对象。
当一个服务调用另一个服务时,Feign 客户端会将 Java 对象转换为 JSON(或其他格式),然后通过 HTTP 请求发送。接收方的服务会将这些 JSON 数据反序列化回 Java 对象。这个过程并不要求 Java 对象实现 Serializable 接口,因为它是基于 HTTP 和消息转换器(如 Jackson JSON 处理库),而不是 Java 原生的序列化机制。
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它可以用于数据的传输和转换。JSON 在不同语言和平台之间传输数据时特别有用,因为它易于人阅读和编写,同时也易于机器解析和生成。在许多现代编程环境和网络应用中,JSON 被广泛用于前后端之间的数据传递,以及不同系统之间的数据交换。JSON 格式因其文本形式和自描述性,成为了 Web API 和微服务架构中常用的数据格式。
序列化不一定需要通过实现 Java 的 Serializable 接口来完成。将对象转换成 JSON、XML 或其他格式也是一种序列化的方法。这些方法允许您将对象的状态转换成一种可以存储或传输的格式,而不依赖于 Java 内置的序列化机制。JSON 和 XML 序列化的优点是它们更加灵活,并且与使用不同编程语言的系统之间的兼容性更好。
换成 JSONObject 通常不会携带有关对象原始类的详细信息,例如类名或属性的数据类型。JSONObject 主要是一种以键值对形式存储数据的结构,其中键通常是字符串,对应对象的字段名称,值是字段的值。这意味着对象的结构会被保留,但不包括其作为特定类实例的信息。当从 JSONObject 反序列化时,您需要知道要将其转换成哪种具体的类类型。虽然 JSON 序列化产生的是文本数据,但这些文本数据最终在存储或传输时仍然以二进制的形式存在(因为所有的文件和网络数据传输本质上都是二进制的)。
在 Spring Boot 应用中,当在 Controller 层将对象转换为 JSON 时,通常这是通过使用 Spring MVC 框架的内置功能自动完成的。这里是一个简单的例子:
@RestController 注解表明这个类是一个 Spring MVC Controller,并且所有的响应都会自动转换成 JSON。
ResponseEntity 用于包装响应对象,Spring MVC 会自动使用 Jackson 或其他配置的 JSON 转换库将 MyObject 实例转换成 JSON 格式。
当客户端请求 /myendpoint 时,方法 getMyObject() 会被调用,返回的 MyObject 对象将被自动序列化为 JSON。
在这段 Spring Boot 控制器代码中,序列化主要发生在将 Java 对象转换为 HTTP 响应的 JSON 数据时。这是由 Spring MVC 框架自动处理的。
Spring Boot 应用中,当您的控制器方法返回一个对象时,Spring MVC 使用配置的消息转换器(默认是 Jackson)将对象转换为 JSON 格式。这个过程与对象是否实现 Serializable 无关。
在 Spring MVC 框架中,对象到 JSON 的自动转换是由 HttpMessageConverter 接口的实现类处理的。具体来说:
MappingJackson2HttpMessageConverter:
这是最常用的转换器,用于处理 JSON 数据。它使用 Jackson 库将 Java 对象转换为 JSON,以及将 JSON 转换为 Java 对象。
配置:
在 Spring MVC 中,这些转换器通常是自动配置的。您可以通过配置 WebMvcConfigurer 来自定义这些转换器的行为。
当一个控制器方法返回对象时,Spring MVC 框架会使用合适的 HttpMessageConverter(如 MappingJackson2HttpMessageConverter)来将对象转换为相应格式的响应体(在大多数情况下是 JSON)。
在 Spring MVC 中,以下几个因素通常指示框架自动处理对象到 JSON 的转换:
@RestController 注解:这个注解表明类中的所有方法返回值都应被视为响应体,并且默认会转换为 JSON。
@ResponseBody 注解:在一个使用 @Controller 注解的类中,@ResponseBody 可以用于具体的方法上,表示该方法的返回结果应该被转换为响应体。
内容协商:Spring MVC 根据请求头(如 Accept)进行内容协商,确定使用哪种格式的响应。
配置的消息转换器:如果项目中配置了 MappingJackson2HttpMessageConverter(默认情况下是有的),它会自动用于转换 JSON。
返回类型:方法的返回类型通常是一个 POJO(普通的 Java 对象),Spring MVC 会尝试将其序列化为 JSON。
HTTP(超文本传输协议)可以传输多种类型的数据,包括但不限于:
文本数据:如 HTML 页面、JSON 或 XML 数据、普通文本等。
数字:作为文本的一部分传输,如查询参数或 JSON/XML 的一部分。
图像和多媒体:如 JPEG、PNG 图像,MP3 音频,MP4 视频等。
二进制数据:任何形式的文件数据,如文档、压缩文件等。
表单数据:通过表单提交的数据,包括文本字段、数字、文件上传等。
所以他可以传递string类型(普通文本) 数字,json等,但是不能传递java对象